Changeset 1313 for cpp/frams/genetics/genooperators.cpp
- Timestamp:
- 07/11/24 17:15:51 (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
cpp/frams/genetics/genooperators.cpp
r1287 r1313 1 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-202 3Maciej Komosinski and Szymon Ulatowski.2 // Copyright (C) 1999-2024 Maciej Komosinski and Szymon Ulatowski. 3 3 // See LICENSE.txt for details. 4 4 … … 56 56 for (sum = 0, i = 0; i < count; i++) { sum += probtab[i]; if (sel < sum) return i; } 57 57 return -1; 58 } 59 60 int GenoOperators::roulette(const vector<double> &probtab) 61 { 62 return roulette(probtab.data(), (int)probtab.size()); 58 63 } 59 64 … … 461 466 } 462 467 463 char *GenoOperators::strchr n0(const char *str, char ch)468 char *GenoOperators::strchr_no0(const char *str, char ch) 464 469 { 465 470 return ch == 0 ? NULL : strchr((char *)str, ch); 466 471 } 467 472 468 int GenoOperators::getRandomChar(const char *choices, const char *excluded) 469 { 470 int allowed_count = 0; 471 for (size_t i = 0; i < strlen(choices); i++) if (!strchrn0(excluded, choices[i])) allowed_count++; 472 if (allowed_count == 0) return -1; //no char is allowed 473 int rnd_index = rndUint(allowed_count) + 1; 474 allowed_count = 0; 475 for (size_t i = 0; i < strlen(choices); i++) 476 { 477 if (!strchrn0(excluded, choices[i])) allowed_count++; 478 if (allowed_count == rnd_index) return int(i); 479 } 480 return -1; //never happens 473 double GenoOperators::probOfModifier(const char* mod_def) 474 { 475 if (*(mod_def + 1) == '(') //the special syntax with the appended probability value in (...) 476 return std::atof(mod_def + 2); //0.0 when no valid number 477 return 1.0; 478 } 479 480 char GenoOperators::getRandomModifier(const char *choices) 481 { 482 static const char* EXTRA_CHARS = "().0123456789"; 483 // this function assumes that EXTRA_CHARS are only used for the special probabilities syntax in "choices", not as valid choice characters. 484 vector<char> allowed; //this could be determined only once for a given "choices", as long as the effect of "choices" is deterministic (i.e., "choices" does not include probabilities) 485 size_t choices_len = strlen(choices); 486 allowed.reserve(choices_len); //max size, avoid reallocations later 487 for (size_t i = 0; i < choices_len; i++) 488 { 489 if (strchr(EXTRA_CHARS, choices[i])) continue; //skip parentheses and numbers 490 double prob = probOfModifier(&choices[i]); 491 if (prob == 1.0 || rndDouble(1) < prob) 492 allowed.push_back(choices[i]); 493 } 494 if (allowed.size() == 0) return 0; //no char is allowed 495 return allowed[rndUint(allowed.size())]; 496 } 497 498 char GenoOperators::getRandomColorModifier(const char *choices, const char *color_modifiers) 499 { 500 vector<char> allowed_colors; 501 vector<double> allowed_probs; 502 size_t colors_len = strlen(color_modifiers); 503 allowed_colors.reserve(colors_len); //max size, avoid reallocations later 504 allowed_probs.reserve(colors_len); //max size, avoid reallocations later 505 for (size_t i = 0; i < colors_len; i++) //for all known color modifiers... 506 { 507 const char *pos = strchr(choices, color_modifiers[i]); //...search in "choices" - i.e., in currently set active modifiers. Note that "choices" may use an extended syntax with numbers and parentheses, such as qM(0.1)Dm(0.1)dG(0.2)C 508 if (pos) //found the color modifier in choices 509 { 510 allowed_colors.push_back(*pos); 511 allowed_probs.push_back(probOfModifier(pos)); 512 } 513 } 514 // the above "parsing" part could be done only once "choices" changes, not every time we want to get a random color modifier... 515 int idx = roulette(allowed_probs); 516 return idx < 0 ? 0 : allowed_colors[idx]; 481 517 } 482 518 … … 544 580 } 545 581 546 string GenoOperators::simplifiedModifiers(const string & original )582 string GenoOperators::simplifiedModifiers(const string & original, const char* colorgenes) 547 583 { 548 584 const int MAX_NUMBER_SAME_TYPE = 5; // max. number of modifiers of each type (case-insensitive). The more characters, the closer we can get to min and max values of a given property at the expense of the length of evolved genotypes. 5 is "close enough", but how close we get to the extreme also depends on the initial value of a given property, which is not always exactly in the middle of min and max. rR is treated separately in simplification because their influence follows different (i.e., simple additive) logic - so the simplifiedModifiersFixedOrder() logic with cancelling out antagonistic modifiers would be appropriate for rR. 585 const int MAX_NUMBER_SAME_TYPE_COLOR = 1; //color does not affect fitness and is used purely for aesthetics, so allow at most 1 char for each r,g,b channel - we get very low resolution of colors (only 3*3*3 combinations), but we spare the genotype length and limit bloat 549 586 int counter[256] = {}; //initialize with zeros; 256 is unnecessarily too big and redundant, but enables very fast access (indexed directly by the ascii code) 550 587 string simplified = ""; … … 556 593 unsigned char lower = std::tolower(c); 557 594 counter[lower]++; 558 if (counter[lower] <= MAX_NUMBER_SAME_TYPE) //get rid of modifiers that are too numerous, but get rid of the first ones in the string (="oldest", the last ones looking from the end), because their influence on the parameter value is the smallest 595 int MAX_NUMBER = strchr(colorgenes, c) != NULL ? MAX_NUMBER_SAME_TYPE_COLOR : MAX_NUMBER_SAME_TYPE; 596 if (counter[lower] <= MAX_NUMBER) //get rid of modifiers that are too numerous - get rid of the first ones in the string (="oldest", the last ones looking from the end), because their influence on the parameter value is the smallest 559 597 simplified += c; 560 598 }
Note: See TracChangeset
for help on using the changeset viewer.