#include //HUGE_VAL #include "geno_f0Fuzzy.h" #include "neuroimpl-fuzzy.h" #include "neuroimpl-fuzzy-f0.h" #include "rndutil.h" #include "model.h" #define FIELDSTRUCT Geno_f0Fuzzy static ParamEntry GENO7param_tab[]= //external access to f0Fuzzy genetic parameters { {"Genetics: f0-fuzzy",1,8,}, {"f0Fuzzy_maxSets",0,0,"Max. sets","d 0 999",FIELD(maximumSetsNr),"Maximum number of fuzzy sets",}, {"f0Fuzzy_maxRules",0,0,"Max. rules","d 0 999",FIELD(maximumRulesNr),"Maximum number of fuzzy rules",}, {"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)",}, {"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)",}, {"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)",}, {"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)",}, {"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)",}, {"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)",}, {0,}, }; #undef FIELDSTRUCT Geno_f0Fuzzy::Geno_f0Fuzzy() { par.setParamTab(GENO7param_tab); par.select(this); supported_format='0'; name="Fuzzy control system"; maximumSetsNr=50; maximumRulesNr=100; probtab[F0Fuzzy_ADDSET] = 0.01; probtab[F0Fuzzy_REMSET] = 0.0112; probtab[F0Fuzzy_ADDRULE]= 0.01; 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 probtab[F0Fuzzy_MODRULE] = 0.005; probtab[F0Fuzzy_MOD2RULE] = 0.005; } char *Geno_f0Fuzzy::getSimplest() { 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"; }; int Geno_f0Fuzzy::markDuplicatedSets(const double fuzzySets1[], const int setsNr1, const double fuzzySets2[], const int setsNr2, int transTable[], const int setsNr3) { if(setsNr1+setsNr2!=setsNr3) return -1; int i, j; for(i=0;i=nrItems) sprintf(temp, "%i", setNr); //might occur when new fuzzy set and new fuzzy rule added - does not need to be transformated else sprintf(temp, "%i", transTable[setNr]); //transformate set number newRules += temp; if(p=nrItems) sprintf(temp, "%i", setNr); //might occur when new fuzzy set and new fuzzy rule added - does not need to be transformated else sprintf(temp, "%i", transTable[setNr]); //transformate set number newRules += temp; if(p=setsNr)||(setNr<0)) setNr=randomN(setsNr); //if everything ok, impossible to happen setUsed[setNr]=true; } p=0; while(dec.getNextToken(p, nrStr, ';')) //first: output number { dec.getNextToken(p, nrStr, ';'); //then fuzzy set nr setNr=atoi(nrStr); if((setNr>=setsNr)||(setNr<0)) setNr=randomN(setsNr); //if everything ok,impossible to happen setUsed[setNr]=true; } } for(i=0, nrUsedSets=0, unusedPresent=false;ii) transTable[j]--; } else nrUsedSets++; SAFEDELETEARRAY(transTableOryginal) if(!unusedPresent) { SAFEDELETEARRAY(setUsed) return 0; //all sets are necessery } //remove from new fuzzy sets unused sets pos=0; newSets=""; int semicol=0, nrOfSet=0; SString tempSet=""; while(sets.getNextToken(pos, nrStr, ';')) { tempSet += nrStr; tempSet += ';'; if(++semicol==4) { if(setUsed[nrOfSet]) newSets += tempSet; tempSet=""; semicol=0; nrOfSet++; } } setsNr=nrUsedSets; sets=newSets; SAFEDELETEARRAY(setUsed) return 1; } int Geno_f0Fuzzy::removeExcessiveInOut(SString &rules, int inputsNr, int outputsNr) { SString newRules, oneRule; int pos, i; char tempChar50[50]; pos=0; while(rules.getNextToken(pos, oneRule, '/')) { SString cond, dec, nrStr, newInput, newOutput; int p=0; bool *usedInOut, first; oneRule.getNextToken(p, cond, ':'); oneRule.getNextToken(p, dec, '/'); //create input table usedInOut = new bool[inputsNr]; for(i=0;i=original_rulesNr) //in fact, it is impossible; but it's safe to protect { SAFEDELETEARRAY(rulDef) if(rulesBody) for(i=0;i0) { int nrOfRule=0; //copy rules, which are not to be removed pos=0; newRules=""; while(rules.getNextToken(pos, oneRule, '/')) if(!rulesToRemove[nrOfRule++]) newRules += oneRule + "/"; rulesNr -= nrRulesToRemove; rules = newRules; } SAFEDELETEARRAY(rulDef) if(rulesBody) for(i=0;i1) set[i]=1; if(set[i]<-1) set[i]=-1; for(j=0;j<4;j++) if((i>j)&&(set[i]getInputCount(); //get number of inputs const int outputsNr=NI_FuzzyNeuro::countOuts(&model, fuzzy); //count number of outputs //get neuron four properties SyntParam pi=fuzzy->classProperties(); model.open(); const int setsNr=pi.getIntById("ns"); const int rulesNr=pi.getIntById("nr"); const SString setsStr=pi.getStringById("fs"); const SString rulesStr=pi.getStringById("fr"); if((inputsNr<=0)||(outputsNr<=0)|| (setsStr.len()==0)||(rulesStr.len()==0)||(setsNr<=0)||(rulesNr<=0)) return GENOPER_OPFAIL; //ERROR //find out the real length of genotype fuzzyGeno = setsStr+", "+rulesStr; genoRemoved=genoAdded=genoUsed=0; //1 geno is i.e. -0.325; but this are 7 characters! so, 1 is used, 6 are unused for(i=0;i=maximumSetsNr) break; double newSetD[4]; computeSet(newSetD); //draw set and rank rising if(sprintf(tempChar50, "%.4lf;%.4lf;%.4lf;%.4lf;", newSetD[0], newSetD[1], newSetD[2], newSetD[3]) != EOF) //in fact, always true { newSetsStr = setsStr + tempChar50; //add new rule, using fresh new created fuzzy set (in premise part) - prevents removing of new fuzzy set 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 (rulesNr=maximumRulesNr) break; SString tempSString; bool ruleOk=true; int nrIns=1+randomN(inputsNr), //draw number of inputs between {1,..,inputsNr} nrOuts=1+randomN(outputsNr); //draw number of outputs between {1,..,outputsNr} for(i=0;((i<(nrIns+nrOuts))&&(ruleOk));i++) if(sprintf(tempChar50, "%i;%i", (i0) tempStr += ";"; //add semic. before input number tempStr += tok + ";"; //input number cond.getNextToken(pos, tok, ';'); tempStr += tok; //set number insFound++; } if((!cond.getNextToken(pos, tok, ';'))||(!cond.getNextToken(pos, tok, ';'))) //ommit selected input break; //error //copy inputs after one to remove while(cond.getNextToken(pos, tok, ';')) { tempStr += ";"; tempStr += tok + ";"; //input number cond.getNextToken(pos, tok, ';'); tempStr += tok; //set number } modRule = newRulesStr + tempStr + ":" + dec + "/"; } else //remove output { int nrOuts=0; while(dec.getNextToken(pos, tok, ';'))nrOuts++; nrOuts = 1 + nrOuts/2; //odd number of semicolons, so 1 + ... if(nrOuts<=1) break; //can not remove - only one input! int nrOutToRem=randomN(nrOuts), outsFound=0; //copy outputs before one to remove while((outsFound0) tempStr += ";"; //add semic. before output number tempStr += tok + ";"; //output number dec.getNextToken(pos, tok, ';'); tempStr += tok; //set number outsFound++; } if((!dec.getNextToken(pos, tok, ';'))||(!dec.getNextToken(pos, tok, ';'))) //ommit selected output break; //error //copy outputs after one to remove while(dec.getNextToken(pos, tok, ';')) { tempStr += ";"; tempStr += tok + ";"; //output number dec.getNextToken(pos, tok, ';'); tempStr += tok; //set number } modRule = newRulesStr + cond + ":" + tempStr + "/"; } tempStr = newRulesStr + modRule; int temp_rulesNr = rulesNr; if((removeExcessiveInOut(tempStr, inputsNr, outputsNr)<0)|| (removeExcessiveRules(tempStr, setsNr, temp_rulesNr)<0)|| (temp_rulesNr != rulesNr)) //removed in/out caused duplicated rule, so this mutation is not ok - try other break; newRulesStr = tempStr; newRulesNr = rulesNr; newSetsStr = setsStr; newSetsNr = setsNr; genoRemoved+=2; // after removing of an input/output from the rule, an unused fuzzy set may occur //create space for new transformation table int *transTable = new int [newSetsNr]; for(int ii=0;iigetInputCount(); const int outputsDeclared=NI_FuzzyNeuro::countOuts(&model,fuzzy); if((inputsDeclared<=0)||(outputsDeclared<=0)) { if(repair) return GENOPER_OK; else return 1; } //ERROR //get neuron four properties SyntParam pi=fuzzy->classProperties(); model.open(); int setsDeclared=pi.getIntById("ns"); int rulesDeclared=pi.getIntById("nr"); const SString fuzzySets=pi.getStringById("fs"); const SString fuzzyRules=pi.getStringById("fr"); //unrepairable errors: there must be some string! if((fuzzySets.len()==0)||(fuzzyRules.len()==0)) if(repair) return GENOPER_OK; //ERROR else return 2; //ERROR if((!repair)&&((setsDeclared<=0)||(rulesDeclared<=0))) return 2; //ERROR //repair if corrupted if(setsDeclared<=0)setsDeclared=1; if(rulesDeclared<=0)rulesDeclared=1; //now fuzzy sets are defined; each number is separated with semicolon. //acceptables signs are: digits, commas, colons, semicolons. i=j=0; setsFound=0; while (j1) { if(!repair) return j; else set[i] = 1; }//out of range if(set[i]==HUGE_VAL) { if(!repair) return j; else set[i] = (i>0?set[i-1]:-1); }//sets must not be decreasing if(++i==4) { //check if sets are rank rising if((set[0]>set[1])||(set[1]>set[2])||(set[2]>set[3])) { if(!repair) return j; else sortSet(set); } if(sprintf(tempChar50, "%.4lf;%.4lf;%.4lf;%.4lf;", set[0], set[1], set[2], set[3]) != EOF) {i=0; setsFound++; repairedSets += tempChar50;} //copy correct value } if((setsFound==setsDeclared)&&(repair)) break; //found enough sets - if there were some sets left, omit them } // valitadion: if there were more sets than declares, nothing happens, because pointer is now after comma (end of all sets) // checking: error if((setsFound!=setsDeclared)&&(!repair)) return j; //ERROR - wrong number of fuzzy sets in definition or abnormal end of the string //now fuzzy rules are defined; each number is separated with semicolon, conditional and decisional part is separated with colon, rules are separated with slash //acceptables signs are: digits, semicolons, colons, slashes. i=0; rulesFound=0; pos=0; while (posinputsDeclared)&&(!repair)) return j+pos; //ERROR: too many inputs //when repair: if inputsUsedNr > declared, do nothing, because later in loop it is checked whether //there is no duplicate input number (the only possible way of situation where inputsUsedNr > declared) //check how many outputs is used: colons=posRule=0; while(++posRuleoutputsDeclared)&&(!repair)) return j+pos; //ERROR: too many outputs //when repair: if outputsUsedNr > declared, do nothing, because later in loop it is checked, wether //there is no duplicate output number (the only possible way of situation where outputsUsedNr > declared) inoutUsed = new int[max(inputsDeclared,outputsDeclared)]; for(i=0;i=inputsDeclared) {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=inputsDeclared-1; } if(inoutUsed[tempVal]==-1) //input is used { ruleCondisSStr.getNextToken(posTemp,nrSStr,';'); //omit input and fuzzy set if(i+1 == inputsUsedNr) repairedRules += ":"; //the end of conditional part - must be here, because of continue if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else continue;//next for loop } else inoutUsed[tempVal]=-1; //used by input if(!firstInput) repairedRules += ";"; //before input there is semicolon, except of begin of the rule firstInput=false; //tempVal now has a correct value sprintf(tempChar50, "%i;", tempVal); //correct input number: repairedRules += tempChar50; //check fuzzy set nr acceptSigns = ""; posOld=posTemp; ruleCondisSStr.getNextToken(posTemp,nrSStr,';'); for(int ii=0;ii=outputsDeclared) {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=outputsDeclared-1; } if(inoutUsed[tempVal]==1) //output is used { ruleDecisSStr.getNextToken(posTemp,nrSStr,';'); //omit output and fuzzy set if (i+1 == inputsUsedNr+outputsUsedNr) repairedRules += "/"; //the end of decisional part - must be here, because of continue if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else continue; //next for loop } else inoutUsed[tempVal]=1; //used by output if(!firstOutput) repairedRules += ";"; //before output there is semicolon, except of begin of the decisional part of the rule firstOutput=false; //tempVal now has a correct value sprintf(tempChar50, "%i;", tempVal); //correct output number: repairedRules += tempChar50; //check fuzzy set nr acceptSigns = ""; posOld=posTemp; ruleDecisSStr.getNextToken(posTemp,nrSStr,';'); for(int ii=0;ii=setsFound) {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=setsFound-1; } //tempVal now has a correct value sprintf(tempChar50, "%i", tempVal); //correct set number: repairedRules += tempChar50; if(i+1 == inputsUsedNr) repairedRules += ":"; //the end of conditional part else if (i+1 == inputsUsedNr+outputsUsedNr) repairedRules += "/"; //the end of decisional part } SAFEDELETEARRAY(inoutUsed) rulesFound++; if ((rulesFound>=rulesDeclared)&&(repair)) break; //if there was more rules - omit them by not parsing any more if ((rulesFound>rulesDeclared)&&(!repair)) return j+pos; // ERROR - too many rules - stop parsing } if ((rulesFound!=rulesDeclared)&&(!repair)) return j+pos; // ERROR - wrong number of rules (too few) if(rulesFound<1) //could happen, when there is one rule and it is unrepairable { if(sprintf(tempChar50, "%i;%i:%i;%i/", randomN(inputsDeclared), randomN(setsFound), randomN(outputsDeclared), randomN(setsFound)) != EOF) repairedRules += tempChar50; //add simple random rule else //on error - add zeros repairedRules += "0;0:0;0/"; //add the simplies rule, but almost impossible to happen rulesFound=1; } //when changing sets numerations, rules might change and equals if((repair)&&(removeExcessiveRules(repairedRules, setsFound, rulesFound)<0)) return GENOPER_OPFAIL; //ERROR //update new genotype pi.setIntById("ns", setsFound); pi.setIntById("nr", rulesFound); pi.setStringById("fs",repairedSets); pi.setStringById("fr",repairedRules); pi.update(); //force commit changes model.close(); //get creature whole genotype finalGenotype=model.getF0Geno().getGene(); //replace old genotype with new one free(geno); geno=strdup((const char*)finalGenotype); return GENOPER_OK; }; int Geno_f0Fuzzy::checkValidity(const char *geno) { char *genoCopy=strdup(geno); int res=checkOrValidate(genoCopy, false); //false = on errors do not repair but return error position free(genoCopy); return res; }; int Geno_f0Fuzzy::validate(char *&geno) { checkOrValidate(geno, true); //true = on errors try to repair but might be unrepairable return GENOPER_OK; }; int Geno_f0Fuzzy::crossOver(char *&g1, char *&g2, float &chg1,float &chg2) { //both bodies should be the same; the only difference should be in fuzzy neuron SString finalGenotype, tok1, tok2; SString fuzzyGeno1, fuzzyGeno2, newSet, sets3, rules3; int setsNr3, rulesNr3; int i, j, k, unimpTemp; int *transTable, *parentsIn, *parentsOut, *parentRules, *rulDef1, *rulDef2, *rulDef3, **rulesBody1, **rulesBody2; int genoUsed1, genoUsed2, copied1, copied2, rulesTaken1, rulesTaken2, rulesUsed3, selectedRule1, selectedRule2; int inputsUsed, outputsUsed; char tempChar50[50]; double *fuzzySets1, *fuzzySets2, *fuzzySets3; Model model1(Geno(g1,'0')); Model model2(Geno(g2,'0')); Neuro *fuzzy1=findNeuro(&model1, Neuro::getClass("Fuzzy")); Neuro *fuzzy2=findNeuro(&model2, Neuro::getClass("Fuzzy")); if (!fuzzy1 || !fuzzy2) return GENOPER_OPFAIL; //ERROR const int inputsNr1=fuzzy1->getInputCount(); const int inputsNr2=fuzzy2->getInputCount(); const int outputsNr1=NI_FuzzyNeuro::countOuts(&model1,fuzzy1); const int outputsNr2=NI_FuzzyNeuro::countOuts(&model2,fuzzy2); if((inputsNr1<=0)||(outputsNr1<=0)||(inputsNr2<=0)||(outputsNr2<=0)|| (inputsNr1!=inputsNr2)||(outputsNr1!=outputsNr2)) return GENOPER_OPFAIL; //ERROR //get neurons four properties SyntParam pi1=fuzzy1->classProperties(); SyntParam pi2=fuzzy2->classProperties(); model1.open(); model2.open(); const int setsNr1=pi1.getIntById("ns"); const int setsNr2=pi2.getIntById("ns"); const int rulesNr1=pi1.getIntById("nr"); const int rulesNr2=pi2.getIntById("nr"); const SString sets1=pi1.getStringById("fs"); const SString sets2=pi2.getStringById("fs"); const SString rules1=pi1.getStringById("fr"); const SString rules2=pi2.getStringById("fr"); if((sets1.len()==0)||(rules1.len()==0)||(sets2.len()==0)||(rules2.len()==0)|| (setsNr1<=0)||(rulesNr1<=0)||(setsNr2<=0)||(rulesNr2<=0)) return GENOPER_OPFAIL; //ERROR //find out the real length of genotype - count number of semicolons genoUsed1 = 0; //1 geno is i.e. -0.325; but this are 7 characters! so, 1 is used, 6 are unused fuzzyGeno1 = sets1+", "+rules1; for(i=0;isetsNr1, substract setsNr1 from value to obtain number of fuzzy set from parent 2 sets3 += tempChar50; } else { SAFEDELETEARRAY(fuzzySets1) SAFEDELETEARRAY(fuzzySets2) SAFEDELETEARRAY(fuzzySets3) SAFEDELETEARRAY(transTable) return GENOPER_OPFAIL; //ERROR } } // ------------------------------------- // ------- cross over rules part ------- // ------------------------------------- rules3=""; //draw number of fuzzy rules for the descendant rulesNr3 = min(rulesNr1,rulesNr2) + randomN(abs(rulesNr1-rulesNr2)+1); rulDef1 = new int[2*rulesNr1]; //for each rule, remembers number of inputs and number of outputs used (in rule) rulDef2 = new int[2*rulesNr2]; rulDef3 = new int[2*rulesNr3]; //it will be filled later, with random values FuzzyF0String::countInputsOutputs(rules1, rulDef1, rulesNr1); FuzzyF0String::countInputsOutputs(rules2, rulDef2, rulesNr2); for(i=0;i<2*rulesNr3;i++) rulDef3[i]=-1; //unknown number of inputs/outputs //create space for rules from parent 1 and 2 rulesBody1 = new int*[rulesNr1]; //list of rules that will contain rules body for (i=0;i