Changeset 1233


Ignore:
Timestamp:
05/04/23 00:57:57 (12 months ago)
Author:
Maciej Komosinski
Message:

Added a function that simplifies a sequence of modifier genes (useful in f1 and f4 encodings) by removing antagonistic modifier genes and limiting the number of genes of the same kind

Location:
cpp/frams/genetics
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/genooperators.cpp

    r1226 r1233  
    88#include <common/nonstd_math.h>
    99#include <frams/util/rndutil.h>
     10#include <algorithm> // std::min, std::max
    1011
    1112//
     
    355356}
    356357
    357 int GenoOperators::getRandomChar(const char *choices, const char *excluded)
    358 {
    359         int allowed_count = 0;
    360         for (size_t i = 0; i < strlen(choices); i++) if (!strchrn0(excluded, choices[i])) allowed_count++;
    361         if (allowed_count == 0) return -1; //no char is allowed
    362         int rnd_index = rndUint(allowed_count) + 1;
    363         allowed_count = 0;
    364         for (size_t i = 0; i < strlen(choices); i++)
    365         {
    366                 if (!strchrn0(excluded, choices[i])) allowed_count++;
    367                 if (allowed_count == rnd_index) return int(i);
    368         }
    369         return -1; //never happens
    370 }
    371 
    372 NeuroClass *GenoOperators::parseNeuroClass(char *&s, ModelEnum::ShapeType supported_shapetype)
     358NeuroClass *GenoOperators::parseNeuroClass(char *&s, ModelEnum::ShapeType for_shape_type)
    373359{
    374360        int maxlen = (int)strlen(s);
     
    378364        {
    379365                NeuroClass *nci = Neuro::getClass(i);
    380                 if (!nci->isShapeTypeSupported(supported_shapetype))
     366                if (!nci->isShapeTypeSupported(for_shape_type))
    381367                        continue;
    382368                const char *nciname = nci->name.c_str();
     
    434420}
    435421
     422bool GenoOperators::canStartNeuroClassName(const char firstchar)
     423{
     424        return isupper(firstchar) || firstchar == '|' || firstchar == '@' || firstchar == '*';
     425}
     426
    436427bool GenoOperators::isWS(const char c)
    437428{
     
    466457}
    467458
    468 bool GenoOperators::canStartNeuroClassName(const char firstchar)
    469 {
    470         return isupper(firstchar) || firstchar == '|' || firstchar == '@' || firstchar == '*';
    471 }
     459int GenoOperators::getRandomChar(const char *choices, const char *excluded)
     460{
     461        int allowed_count = 0;
     462        for (size_t i = 0; i < strlen(choices); i++) if (!strchrn0(excluded, choices[i])) allowed_count++;
     463        if (allowed_count == 0) return -1; //no char is allowed
     464        int rnd_index = rndUint(allowed_count) + 1;
     465        allowed_count = 0;
     466        for (size_t i = 0; i < strlen(choices); i++)
     467        {
     468                if (!strchrn0(excluded, choices[i])) allowed_count++;
     469                if (allowed_count == rnd_index) return int(i);
     470        }
     471        return -1; //never happens
     472}
     473
     474//#include <cassert>
     475string GenoOperators::simplifiedModifiers(const char *str_of_char_pairs, vector<int> &char_counts)
     476{
     477//      assert(strlen(str_of_char_pairs) == char_counts.size());
     478//      assert(char_counts.size() % 2 == 0);
     479        const int MAX_NUMBER_SAME_TYPE = 8; // max. number of modifiers of each type = 8 (mainly for Rr)
     480        string simplified;
     481        //#define CLUMP_IDENTICAL_MODIFIERS //not good because properties are calculated incrementally, non-linearly, and their values are updated after each modifier character, so these values may for example saturate after a large number of identical modifier symbols. The order of modifiers is in general relevant and extreme values of properties increase this relevance, so better keep the modifiers dispersed.
     482#ifdef CLUMP_IDENTICAL_MODIFIERS
     483        for (size_t i = 0; i < strlen(str_of_char_pairs); i++)
     484                if ((i % 2) == 0) //only even index "i" in str_of_char_pairs
     485                        for (int j = 0; j < std::min(MAX_NUMBER_SAME_TYPE, abs(char_counts[i] - char_counts[i + 1])); j++) //assume that an even-index char and the following odd-index char have the opposite influence, so they cancel out.
     486                                simplified += str_of_char_pairs[i + (char_counts[i + 1] > char_counts[i])]; //inner loop adds a sequence of same chars such as rrrrr or QQQ
     487#else
     488        for (size_t i = 0; i < strlen(str_of_char_pairs); i++)
     489                if ((i % 2) == 0) //only even index "i" in str_of_char_pairs
     490                {
     491                        char_counts[i] -= char_counts[i + 1]; //from now on, even items in the vector store the difference between antagonistic modifier symbols; odd items are not needed
     492                        char_counts[i] = std::min(std::max(char_counts[i], -MAX_NUMBER_SAME_TYPE), MAX_NUMBER_SAME_TYPE);
     493                }
     494        int remaining;
     495        do {
     496                remaining = 0;
     497                for (size_t i = 0; i < strlen(str_of_char_pairs); i++)
     498                        if ((i % 2) == 0) //only even index "i" in str_of_char_pairs
     499                                if (char_counts[i] != 0)
     500                                {
     501                                        simplified += str_of_char_pairs[i + (char_counts[i] < 0)];
     502                                        char_counts[i] += char_counts[i] > 0 ? -1 : +1; //decrease the difference towards zero
     503                                        remaining += abs(char_counts[i]);
     504                                }
     505        } while (remaining > 0);
     506#endif
     507        return simplified;
     508}
  • cpp/frams/genetics/genooperators.h

    r1226 r1233  
    121121        \retval GENOPER_OPFAIL
    122122        \sa
    123         Mutation example to illustrate the exchange of pointers for \e geno.
    124         The mutation adds random letter at the beginning or removes last letter from \e geno.
     123        Mutation example to illustrate the exchange of pointers for \a geno.
     124        The mutation adds random letter at the beginning or removes last letter from \a geno.
    125125        \code
    126126        {
     
    144144        virtual int mutate(char *&geno, float& chg, int &method) { method = -1; chg = -1; return GENOPER_NOOPER; }
    145145
    146         /**Crosses over two genotypes. It is sufficient to return only one child (in \e g1) and set \e chg1 only, then \e g2 must equal "".
     146        /**Crosses over two genotypes. It is sufficient to return only one child (in \a g1) and set \a chg1 only, then \a g2 must equal "".
    147147
    148148        Avoid unnecessary calls in your code. Every genotype argument passed to this
     
    167167        \param geno genotype
    168168        \param pos 0-based char offset
    169         \retval number-encoded visual style (and validity) of the genotype char at \e geno[pos].
     169        \retval number-encoded visual style (and validity) of the genotype char at \a geno[pos].
    170170        Assume white background.
    171171        \sa GENSTYLE_* macros, like GENSTYLE_BOLD*/
     
    183183        static const int NEUROCLASS_PROP_OFFSET = 100; //a NeuroClass property is identified by some functions below as a single-value integer index, yet a property is either "standard" or "extra" (two separate lists), hence this offset to tell one case from the other.
    184184
    185         static int roulette(const double *probtab, const int count);    ///<returns random index according to probabilities in the \e probtab table or -1 if all probs are zero. \e count is the number of elements in \e probtab.
     185        static int roulette(const double *probtab, const int count);    ///<returns random index according to probabilities in the \a probtab table or -1 if all probs are zero. \a count is the number of elements in \a probtab.
    186186        static bool getMinMaxDef(ParamInterface *p, int propindex, double &mn, double &mx, double &def); ///<perhaps a more useful (higher-level) way to obtain min/max/def info for integer and double properties. Returns true if min/max/def was really available (otherwise it is just invented).
    187187        static bool mutateRandomNeuroClassProperty(Neuro* n); ///<high-level neuron mutation function, will select and mutate a random property of Neuron's NeuroClass. Returns true if successful and some property was actually mutated. Could return false when the NeuroClass of the Neuron have no properties, or when a randomly selected property was not suitable for mutation (for example a string or another non-number type).
    188188        static int selectRandomNeuroClassProperty(Neuro* n); ///<selects random property (either 0-based extraproperty of NeuroClass or NEUROCLASS_PROP_OFFSET-based standard property of NeuroClass). -1 if Neuroclass has no properties.
    189         static double getMutatedNeuroClassProperty(double current, Neuro *n, int propindex); ///<returns value \e current mutated for the property \e propindex of Neuron's NeuroClass or for extraproperty (\e propindex - NEUROCLASS_PROP_OFFSET) of Neuron's NeuroClass. Neuro \e n is used as read-only.
    190         static double getMutatedNeuronConnectionWeight(double current); ///<returns mutated value of \e current.
     189        static double getMutatedNeuroClassProperty(double current, Neuro *n, int propindex); ///<returns value \a current mutated for the property \a propindex of Neuron's NeuroClass or for extraproperty (\a propindex - NEUROCLASS_PROP_OFFSET) of Neuron's NeuroClass. Neuro \a n is used as read-only.
     190        static double getMutatedNeuronConnectionWeight(double current); ///<returns mutated value of \a current.
    191191        static bool mutatePropertyNaive(ParamInterface &p, int propindex); ///<creep-mutate selected property. Returns true when success. mutateProperty() should be used instead of this function.
    192192        static bool mutateProperty(ParamInterface &p, int propindex); ///<like mutatePropertyNaive(), but uses special probability distributions for some neuron properties.
    193         static bool getMutatedProperty(ParamInterface &p, int i, double oldval, double &newval); ///<like mutateProperty(), but just returns \e newval, does not get nor set it using \e p.
    194         static double mutateCreepNoLimit(char type, double current, double stddev, bool limit_precision_3digits); ///<returns \e current value creep-mutated with Gaussian distribution and \e stddev standard deviation. Precision limited to 3 digits after comma when \e limit_precision_3digits is true. \e type must be either 'd' (integer) or 'f' (float/double).
     193        static bool getMutatedProperty(ParamInterface &p, int i, double oldval, double &newval); ///<like mutateProperty(), but just returns \a newval, does not get nor set it using \a p.
     194        static double mutateCreepNoLimit(char type, double current, double stddev, bool limit_precision_3digits); ///<returns \a current value creep-mutated with Gaussian distribution and \a stddev standard deviation. Precision limited to 3 digits after comma when \a limit_precision_3digits is true. \a type must be either 'd' (integer) or 'f' (float/double).
    195195        static double mutateCreep(char type, double current, double mn, double mx, double stddev, bool limit_precision_3digits); ///<just as mutateCreepNoLimit(), but forces mutated value into the [mn,mx] range using the 'reflect' approach.
    196         static double mutateCreep(char type, double current, double mn, double mx, bool limit_precision_3digits); ///<just as mutateCreepNoLimit(), but forces mutated value into the [\e mn,\e mx] range using the 'reflect' approach and assumes standard deviation to be a fraction of the mx-mn interval width.
     196        static double mutateCreep(char type, double current, double mn, double mx, bool limit_precision_3digits); ///<just as mutateCreepNoLimit(), but forces mutated value into the [\a mn,\a mx] range using the 'reflect' approach and assumes standard deviation to be a fraction of the mx-mn interval width.
    197197        static void setIntFromDoubleWithProbabilisticDithering(ParamInterface &p, int index, double value); ///<sets a double value in an integer field; when a value is non-integer, applies random "dithering" so that both lower and higher integer value have some chance to be set.
    198198        static void linearMix(vector<double> &p1, vector<double> &p2, double proportion); ///<mixes two real-valued vectors; inherited proportion should be within [0,1]; 1.0 does not change values (all inherited), 0.5 causes both vectors to become their average, 0.0 swaps values (none inherited).
    199199        static void linearMix(ParamInterface &p1, int i1, ParamInterface &p2, int i2, double proportion); ///<mixes i1'th and i2'th properties of p1 and p2; inherited proportion should be within [0,1]; 1.0 does not change values (all inherited), 0.5 causes both properties to become their average, 0.0 swaps values (none inherited). For integer properties applies random "dithering" when necessary.
     200
    200201        static int getActiveNeuroClassCount(Model::ShapeType for_shape_type); ///<returns active class count
    201202        static NeuroClass* getRandomNeuroClass(Model::ShapeType for_shape_type); ///<returns random neuroclass or NULL when no active classes.
     
    204205        static NeuroClass* getRandomNeuroClassWithOutputAndWantingNoInputs(Model::ShapeType for_shape_type); ///<returns random sensor or NULL when no active classes. Note: only neuroclasses that prefer 0 inputs are considered, not those that prefer any number of inputs (thus including 0) - see getRandomNeuroClassWithOutputAndWantingNoOrAnyInputs().
    205206        static NeuroClass* getRandomNeuroClassWithOutputAndWantingNoOrAnyInputs(Model::ShapeType for_shape_type); ///<returns random neuron or NULL when no active classes. Note: both neuroclasses that prefer 0 inputs and those that prefer any number of inputs (thus including 0) are considered.
    206         static int getRandomNeuroClassWithOutput(const vector<NeuroClass*>& NClist); ///<returns index of random NeuroClass from the NClist or -1 when no neurons in the list provide output \e NClist list of available neuron classes
    207         static int getRandomNeuroClassWithInput(const vector<NeuroClass*>& NClist); ///<returns index of random NeuroClass from the NClist or -1 when no neurons in the list want input(s) \e NClist list of available neuron classes
    208         static int getRandomChar(const char *choices, const char *excluded); ///<returns index of a random character from \e choices excluding \e excluded, or -1 when everything is excluded or \e choices is empty.
    209         static NeuroClass* parseNeuroClass(char *&s, ModelEnum::ShapeType supported_shapetype); ///<returns the longest matching neuroclass that satisfies supported_shapetype (ModelEnum::SHAPETYPE_BALL_AND_STICK or ModelEnum::SHAPETYPE_SOLIDS) or NULL if the string does not begin with an appropriate neuroclass name. Advances the \e s pointer if the neuroclass is found.
    210         static Neuro* findNeuro(const Model *m, const NeuroClass *nc); ///<returns pointer to first Neuro of class \e nc, or NULL if there is no such Neuro.
    211         static int neuroClassProp(char *&s, NeuroClass *nc, bool also_v1_N_props = false); ///<returns 0-based extraproperty of NeuroClass or NEUROCLASS_PROP_OFFSET-based standard property of NeuroClass, or -1 if the string does not begin with a valid property name. Advance the \e s pointer if success.
    212         static bool isWS(const char c); ///<is \e c a whitespace char?
    213         static void skipWS(char *&s); ///<advances pointer \e s skipping whitespaces.
     207        static int getRandomNeuroClassWithOutput(const vector<NeuroClass*>& NClist); ///<returns index of random NeuroClass from the NClist or -1 when no neurons in the list provide output \a NClist list of available neuron classes
     208        static int getRandomNeuroClassWithInput(const vector<NeuroClass*>& NClist); ///<returns index of random NeuroClass from the NClist or -1 when no neurons in the list want input(s) \a NClist list of available neuron classes
     209        static NeuroClass* parseNeuroClass(char *&s, ModelEnum::ShapeType for_shape_type); ///<returns the longest matching neuroclass that supports for_shape_type (ModelEnum::SHAPETYPE_BALL_AND_STICK or ModelEnum::SHAPETYPE_SOLIDS) or NULL if the string does not begin with an appropriate neuroclass name. Advances the \a s pointer if the neuroclass is found.
     210        static Neuro* findNeuro(const Model *m, const NeuroClass *nc); ///<returns pointer to first Neuro of class \a nc, or NULL if there is no such Neuro.
     211        static int neuroClassProp(char *&s, NeuroClass *nc, bool also_v1_N_props = false); ///<returns 0-based extraproperty of NeuroClass or NEUROCLASS_PROP_OFFSET-based standard property of NeuroClass, or -1 if the string does not begin with a valid property name. Advance the \a s pointer if success.
     212        static bool canStartNeuroClassName(const char firstchar); ///<determines if \a firstchar may start NeuroClass name. If not, it might start NeuroClass' (or Neuro's) property name.
     213
     214        static bool isWS(const char c); ///<is \a c a whitespace char?
     215        static void skipWS(char *&s); ///<advances pointer \a s skipping whitespaces.
    214216        static bool areAlike(char*, char*); ///<compares two text strings skipping whitespaces. Returns 1 when equal, 0 when different.
    215         static char* strchrn0(const char *str, char ch); ///<like strchr, but does not find zero char in \e str.
    216         static bool canStartNeuroClassName(const char firstchar); ///<determines if \e firstchar may start NeuroClass name. If not, it might start NeuroClass' (or Neuro's) property name.
    217 
    218 
     217        static char* strchrn0(const char *str, char ch); ///<like strchr, but does not find zero char in \a str.
     218
     219        static int getRandomChar(const char *choices, const char *excluded); ///<returns index of a random character from \a choices excluding \a excluded, or -1 when everything is excluded or \a choices is empty.
     220        static string simplifiedModifiers(const char *str_of_char_pairs, vector<int> &char_counts); ///<returns a sequence of chars from \a str_of_char_pairs based on how many times each char occurred in \a char_counts. Assume that an even-index char and the following odd-index char have the opposite influence, so they cancel out.
    219221        //@}
    220222};
Note: See TracChangeset for help on using the changeset viewer.