- Timestamp:
- 06/22/23 03:29:05 (18 months ago)
- Location:
- cpp/frams/genetics
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
cpp/frams/genetics/genooperators.cpp
r1247 r1254 5 5 #include <ctype.h> //isupper() 6 6 #include <algorithm> // std::min, std::max 7 #include <cmath> // std::floor() 7 8 #include "genooperators.h" 8 9 #include <common/log.h> … … 203 204 if (result > mx) result = mx - (result - mx); else 204 205 if (result < mn) result = mn + (mn - result); 205 //wrap (just in case 'result' exceeded the allowed range so much that after reflection above it exceeded the other boundary):206 //wrap (just in case 'result' exceeded the allowed range so much that after the reflection above it exceeded the other boundary): 206 207 if (result > mx) result = mn + fmod(result - mx, mx - mn); else 207 208 if (result < mn) result = mn + fmod(mn - result, mx - mn); … … 210 211 //reflect and wrap above may have changed the (limited) precision, so try to round again (maybe unnecessarily, because we don't know if reflect+wrap above were triggered) 211 212 double result_try = round(result, 3); 212 if (mn <= result_try && result_try <= mx) result = result_try; //after rounding still witin allowed range, so keep rounded value 213 } 214 } 213 if (mn <= result_try && result_try <= mx) result = result_try; //after rounding still within allowed range, so keep rounded value 214 } 215 } 216 clipNegativeZeroIfNeeded(result, mn); //so we don't get -0.0 when minimum is 0.0 215 217 return result; 216 218 } … … 222 224 } 223 225 224 void GenoOperators::setIntFromDoubleWithProbabilisticDithering(ParamInterface &p, int index, double value) //TODO 225 { 226 p.setInt(index, (paInt)(value + 0.5)); //TODO value=2.499 will result in 2 and 2.5 will result in 3, but we want these cases to be 2 or 3 with almost equal probability. value=2.1 should be mostly 2, rarely 3. Careful with negative values (test it!) 226 void GenoOperators::setIntFromDoubleWithProbabilisticDithering(ParamInterface &p, int index, double value) 227 { 228 // Deterministic rounding to the closest integer: 229 //value += 0.5; // value==2.499 will become int 2 and value==2.5 will become int 3, but we want these cases to be 2 or 3 with almost equal probability (stochastic rounding). 230 231 //stochastic rounding (value==2.1 should turn in most cases to int 2, rarely to int 3; value==-2.1 should become mostly int -2, rarely int -3): 232 double lower = std::floor(value); 233 value = rndDouble(1) < (value - lower) ? lower + 1 : lower; 234 235 p.setInt(index, (paInt)value); 227 236 } 228 237 -
cpp/frams/genetics/genooperators.h
r1243 r1254 195 195 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 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. 197 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.197 static void setIntFromDoubleWithProbabilisticDithering(ParamInterface &p, int index, double value); ///<sets a double value in an integer field; when a value is non-integer, applies stochastic rounding (random "dithering") so that both lower and higher integer value have some chance to be set. 198 198 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). 199 199 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. … … 221 221 static string simplifiedModifiersFixedOrder(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. We don't use this function, because a fixed order imposed by this function means that the number of different parameter values produced by a sequence of modifiers is lowered (N same-letter upper- and lower-case chars yield only 2*N different values). Due to how modifiers work, the effect of aaA, aAa, Aaa etc. is different (N same-letter upper- and lower-case chars yield 2^N different values), so simplifying modifiers should not impose any order, should not interfere with their original order, and should not cancel out antagonistic modifiers - see \a simplifiedModifiers() and geneprops_test.cpp. 222 222 //@} 223 static string simplifiedModifiers(const string &original); ///<from the \a original sequence removes modifiers that are too numerous (exceeding a defined threshold number), starting the removal from the le ftmost (="oldest" when interpreting the sequence from left to right) ones.223 static string simplifiedModifiers(const string &original); ///<from the \a original sequence removes modifiers that are too numerous (exceeding a defined threshold number), starting the removal from the least-significant, leftmost (="oldest" when interpreting the sequence from left to right) ones. Contrary to \a simplifiedModifiersFixedOrder(), this kind of simplification preserves 2^N different sequences for each upper/lower-case modifier and thus 2^N different values of a given property (see geneprops.cpp), but the values resulting from these sequences constitute a landscape not as easy for optimization as in the case of 2*N, where the effect of each mutation could be independent and additive (no epistasis). So for a given sequence length, the 2^N case allows for a higher resolution at the cost of a more rugged fitness landscape than the 2*N case. 224 224 }; 225 225
Note: See TracChangeset
for help on using the changeset viewer.