1 | // This file is a part of Framsticks SDK. http://www.framsticks.com/ |
---|
2 | // Copyright (C) 1999-2023 Maciej Komosinski and Szymon Ulatowski. |
---|
3 | // See LICENSE.txt for details. |
---|
4 | |
---|
5 | #include "geneprops.h" |
---|
6 | #include <algorithm> |
---|
7 | |
---|
8 | GeneProps GeneProps::standard_values; |
---|
9 | |
---|
10 | GeneProps::GeneProps() |
---|
11 | { |
---|
12 | Part_MinMaxDef default_part = Model::getDefPart(); |
---|
13 | Joint default_joint = Model::getDefJoint(); |
---|
14 | |
---|
15 | length = 1.0; |
---|
16 | weight = 1.0; |
---|
17 | friction = default_part.friction; |
---|
18 | curvedness = 0.0; |
---|
19 | twist = 0.0; |
---|
20 | energy = 1.0; |
---|
21 | |
---|
22 | // before 2023-05, the four fields below were aggregated and normalized using normalizeBiol4(), but this normalization only worked for f1 and f4 - other genetic encodings do not perform such normalization. If at all, this should be handled by the expdef depending on the goal of the experiment (e.g., to encourage specialization). |
---|
23 | muscle_power = 0.25; // "biological" property, same as findNeuroClass("BendMuscle or RotMuscle")->paraminterface->getDoubleById("power") |
---|
24 | assimilation = default_part.assim; // "biological" property |
---|
25 | stamina = default_joint.stamina; // "biological" property |
---|
26 | ingestion = default_part.ingest; // "biological" property |
---|
27 | |
---|
28 | muscle_bend_range = 1.0; // same as findNeuroClass("BendMuscle")->paraminterface->getDoubleById("range") |
---|
29 | muscle_reset_range = true; |
---|
30 | |
---|
31 | cred = default_part.vcolor.x; |
---|
32 | cgreen = default_part.vcolor.y; |
---|
33 | cblue = default_part.vcolor.z; |
---|
34 | } |
---|
35 | |
---|
36 | void GeneProps::normalizeBiol4() |
---|
37 | { |
---|
38 | // make them sum to 1 |
---|
39 | double sum = muscle_power + assimilation + stamina + ingestion; |
---|
40 | if (sum == 0) |
---|
41 | { |
---|
42 | muscle_power = assimilation = stamina = ingestion = 0.25; |
---|
43 | } |
---|
44 | else |
---|
45 | { |
---|
46 | muscle_power /= sum; |
---|
47 | assimilation /= sum; |
---|
48 | stamina /= sum; |
---|
49 | ingestion /= sum; |
---|
50 | } |
---|
51 | } |
---|
52 | |
---|
53 | int GeneProps::executeModifier_Legacy(char modif) |
---|
54 | { |
---|
55 | switch (modif) |
---|
56 | { |
---|
57 | #ifdef v1f1COMPATIBLE |
---|
58 | case 'L': length += (3.0 - length) * 0.3; |
---|
59 | length = std::min(length, Model::getMaxJoint().d.x); break; |
---|
60 | #else |
---|
61 | case 'L': length += (2.0 - length) * 0.3; //2.0 is currently Model::getMaxJoint().d.x so min() does not limit the range |
---|
62 | length = std::min(length, Model::getMaxJoint().d.x); break; |
---|
63 | #endif |
---|
64 | case 'l': length += (0.33 - length) * 0.3; |
---|
65 | length = std::max(length, Model::getMinJoint().d.x); break; |
---|
66 | |
---|
67 | case 'W': weight += (2.0 - weight) * 0.3; break; |
---|
68 | case 'w': weight += (0.5 - weight) * 0.3; break; |
---|
69 | case 'F': friction += (4 - friction) * 0.2; break; |
---|
70 | case 'f': friction -= friction * 0.2; break; |
---|
71 | case 'C': curvedness += (2.0 - curvedness) * 0.25; break; |
---|
72 | case 'c': curvedness += (-2.0 - curvedness) * 0.25; break; |
---|
73 | case 'Q': twist += (M_PI_2 - twist) * 0.3; break; |
---|
74 | case 'q': twist += (-M_PI_2 - twist) * 0.3; break; |
---|
75 | case 'E': energy += (10.0 - energy) * 0.1; break; |
---|
76 | case 'e': energy -= energy * 0.1; break; |
---|
77 | |
---|
78 | case 'A': assimilation += (1 - assimilation) * 0.8; normalizeBiol4(); break; |
---|
79 | case 'a': assimilation -= assimilation * 0.4; normalizeBiol4(); break; |
---|
80 | case 'I': ingestion += (1 - ingestion) * 0.8; normalizeBiol4(); break; |
---|
81 | case 'i': ingestion -= ingestion * 0.4; normalizeBiol4(); break; |
---|
82 | case 'S': stamina += (1 - stamina) * 0.8; normalizeBiol4(); break; |
---|
83 | case 's': stamina -= stamina * 0.4; normalizeBiol4(); break; |
---|
84 | case 'M': muscle_power += (1 - muscle_power) * 0.8; normalizeBiol4(); break; |
---|
85 | case 'm': muscle_power -= muscle_power * 0.4; normalizeBiol4(); break; |
---|
86 | |
---|
87 | case 'D': cred += (1.0 - cred) * 0.25; break; |
---|
88 | case 'd': cred += (0.0 - cred) * 0.25; break; |
---|
89 | case 'G': cgreen += (1.0 - cgreen) * 0.25; break; |
---|
90 | case 'g': cgreen += (0.0 - cgreen) * 0.25; break; |
---|
91 | case 'B': cblue += (1.0 - cblue) * 0.25; break; |
---|
92 | case 'b': cblue += (0.0 - cblue) * 0.25; break; |
---|
93 | |
---|
94 | default: return -1; |
---|
95 | } |
---|
96 | return 0; |
---|
97 | } |
---|
98 | |
---|
99 | int GeneProps::executeModifier(char modif, GenePropsOps* ops) |
---|
100 | { |
---|
101 | if (ops == NULL) |
---|
102 | ops = getStandardOps(); |
---|
103 | |
---|
104 | #define APPLY(name) ops->name->apply(name, modif) |
---|
105 | #define APPLY_AND_MAYBE_NORMALIZEBIOL4(name) {APPLY(name); if (ops->use_normalizebiol4) normalizeBiol4();} |
---|
106 | |
---|
107 | switch (toupper(modif)) |
---|
108 | { |
---|
109 | case 'L': APPLY(length); |
---|
110 | length = std::min(length, Model::getMaxJoint().d.x); break; |
---|
111 | break; |
---|
112 | |
---|
113 | case 'l': APPLY(length); |
---|
114 | length = std::max(length, Model::getMinJoint().d.x); break; |
---|
115 | break; |
---|
116 | |
---|
117 | case 'W': APPLY(weight); break; |
---|
118 | case 'F': APPLY(friction); break; |
---|
119 | case 'C': APPLY(curvedness); break; |
---|
120 | case 'Q': APPLY(twist); break; |
---|
121 | case 'E': APPLY(energy); break; |
---|
122 | |
---|
123 | case 'A': APPLY_AND_MAYBE_NORMALIZEBIOL4(assimilation); break; |
---|
124 | case 'I': APPLY_AND_MAYBE_NORMALIZEBIOL4(ingestion); break; |
---|
125 | case 'S': APPLY_AND_MAYBE_NORMALIZEBIOL4(stamina); break; |
---|
126 | case 'M': APPLY_AND_MAYBE_NORMALIZEBIOL4(muscle_power); break; |
---|
127 | |
---|
128 | case 'D': APPLY(cred); break; |
---|
129 | case 'G': APPLY(cgreen); break; |
---|
130 | case 'B': APPLY(cblue); break; |
---|
131 | |
---|
132 | default: return -1; |
---|
133 | } |
---|
134 | return 0; |
---|
135 | |
---|
136 | #undef APPLY |
---|
137 | #undef APPLY_AND_MAYBE_NORMALIZEBIOL4 |
---|
138 | } |
---|
139 | |
---|
140 | void GeneProps::propagateAlong(bool use_f1_muscle_reset_range, GenePropsOps* ops) |
---|
141 | { |
---|
142 | length = 0.5 * length + 0.5 * standard_values.length; |
---|
143 | weight += (standard_values.weight - weight) * 0.5; |
---|
144 | friction = 0.8 * friction + 0.2 * standard_values.friction; |
---|
145 | curvedness = 0.66 * curvedness; |
---|
146 | twist = 0.66 * twist; |
---|
147 | |
---|
148 | assimilation = 0.8 * assimilation + 0.2 * standard_values.assimilation; |
---|
149 | ingestion = 0.8 * ingestion + 0.2 * standard_values.ingestion; |
---|
150 | stamina = 0.8 * stamina + 0.2 * standard_values.stamina; |
---|
151 | muscle_power = 0.8 * muscle_power + 0.2 * standard_values.muscle_power; |
---|
152 | |
---|
153 | if (ops == NULL) |
---|
154 | ops = getStandardOps(); |
---|
155 | if (ops->use_normalizebiol4) normalizeBiol4(); |
---|
156 | |
---|
157 | if (use_f1_muscle_reset_range) |
---|
158 | { |
---|
159 | if (muscle_reset_range) muscle_bend_range = 1.0; else muscle_reset_range = true; |
---|
160 | } |
---|
161 | } |
---|
162 | |
---|
163 | //////////////////////////////////////////////////// |
---|
164 | |
---|
165 | void GenePropsOp::apply(double &value, char modif) const |
---|
166 | { |
---|
167 | if (isupper(modif)) |
---|
168 | value = increase(value); |
---|
169 | else |
---|
170 | value = decrease(value); |
---|
171 | } |
---|
172 | |
---|
173 | double GenePropsOp_Old::increase(double value) const |
---|
174 | { |
---|
175 | return value + (maxvalue - value) * change; |
---|
176 | } |
---|
177 | |
---|
178 | double GenePropsOp_Old::decrease(double value) const |
---|
179 | { |
---|
180 | return value + (minvalue - value) * revchange; |
---|
181 | } |
---|
182 | |
---|
183 | GenePropsOp_Old::GenePropsOp_Old(double minvalue, double maxvalue, double defvalue, double change, double revchange) |
---|
184 | { |
---|
185 | this->minvalue = minvalue; |
---|
186 | this->maxvalue = maxvalue; |
---|
187 | this->defvalue = defvalue; |
---|
188 | this->change = change; |
---|
189 | this->revchange = (revchange < 0) ? change : revchange; |
---|
190 | } |
---|
191 | |
---|
192 | GenePropsOp_Exponential::GenePropsOp_Exponential(double minvalue, double maxvalue, double defvalue, double change) |
---|
193 | :GenePropsOp_NormalizedAndScaled(change) |
---|
194 | { |
---|
195 | double mid = (maxvalue + minvalue) / 2; |
---|
196 | if (fabs(mid - defvalue) < 0.01) |
---|
197 | { |
---|
198 | linear = true; |
---|
199 | a = (maxvalue - minvalue) / 2; |
---|
200 | b = defvalue; |
---|
201 | } |
---|
202 | else |
---|
203 | { |
---|
204 | linear = false; |
---|
205 | a = -(maxvalue - defvalue) / (minvalue - defvalue); |
---|
206 | b = (minvalue * minvalue - 2 * defvalue * minvalue + defvalue * defvalue) / (minvalue + maxvalue - 2 * defvalue); |
---|
207 | c = (maxvalue * minvalue - defvalue * defvalue) / (minvalue + maxvalue - 2 * defvalue); |
---|
208 | log_a = log(a); |
---|
209 | } |
---|
210 | } |
---|
211 | |
---|
212 | double GenePropsOp_Exponential::scale(double value) const |
---|
213 | { |
---|
214 | if (linear) |
---|
215 | return a * value + b; |
---|
216 | else |
---|
217 | return pow(a, (value + 1)) * b + c; |
---|
218 | } |
---|
219 | |
---|
220 | double GenePropsOp_Exponential::scaleInv(double value) const |
---|
221 | { |
---|
222 | if (linear) |
---|
223 | return (value - b) / a; |
---|
224 | else |
---|
225 | return -(log_a - log(value / b - c / b)) / log_a; |
---|
226 | } |
---|
227 | |
---|
228 | //////////////////////////////////////////////////////////////////// |
---|
229 | |
---|
230 | |
---|
231 | GenePropsOps::~GenePropsOps() |
---|
232 | { |
---|
233 | delete length; |
---|
234 | delete curvedness; |
---|
235 | delete weight; |
---|
236 | delete friction; |
---|
237 | delete muscle_power; |
---|
238 | delete assimilation; |
---|
239 | delete stamina; |
---|
240 | delete ingestion; |
---|
241 | delete twist; |
---|
242 | delete energy; |
---|
243 | delete cred; |
---|
244 | delete cgreen; |
---|
245 | delete cblue; |
---|
246 | } |
---|
247 | |
---|
248 | GenePropsOps_Old::GenePropsOps_Old() |
---|
249 | { |
---|
250 | use_normalizebiol4 = true; |
---|
251 | |
---|
252 | length = new GenePropsOp_Old(0.33, 2.0, GeneProps::standard_values.length, 0.3); |
---|
253 | weight = new GenePropsOp_Old(0.5, 2.0, GeneProps::standard_values.weight, 0.3); |
---|
254 | friction = new GenePropsOp_Old(0, 4.0, GeneProps::standard_values.friction, 0.2); |
---|
255 | curvedness = new GenePropsOp_Old(-2, 2, GeneProps::standard_values.curvedness, 0.25); |
---|
256 | twist = new GenePropsOp_Old(-M_PI_2, M_PI_2, GeneProps::standard_values.twist, 0.3); |
---|
257 | energy = new GenePropsOp_Old(0, 10, GeneProps::standard_values.energy, 0.1); |
---|
258 | |
---|
259 | assimilation = new GenePropsOp_Old(0, 1, GeneProps::standard_values.assimilation, 0.8, 0.4); |
---|
260 | ingestion = new GenePropsOp_Old(0, 1, GeneProps::standard_values.ingestion, 0.8, 0.4); |
---|
261 | stamina = new GenePropsOp_Old(0, 1, GeneProps::standard_values.stamina, 0.8, 0.4); |
---|
262 | muscle_power = new GenePropsOp_Old(0, 1, GeneProps::standard_values.muscle_power, 0.8, 0.4); |
---|
263 | |
---|
264 | cred = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cred, 0.25); |
---|
265 | cgreen = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cgreen, 0.25); |
---|
266 | cblue = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cblue, 0.25); |
---|
267 | } |
---|
268 | |
---|
269 | GenePropsOps_New05::GenePropsOps_New05() |
---|
270 | { |
---|
271 | use_normalizebiol4 = false; |
---|
272 | auto fields = { length,curvedness,weight,friction,muscle_power,assimilation,stamina,ingestion,twist,energy,cred,cgreen,cblue }; |
---|
273 | for (auto f : fields) |
---|
274 | { |
---|
275 | auto f_gpo = dynamic_cast<GenePropsOp_Old*>(f); |
---|
276 | if (f_gpo) |
---|
277 | f_gpo->change = f_gpo->revchange = 0.5; |
---|
278 | } |
---|
279 | } |
---|
280 | |
---|
281 | GenePropsOps_Exponential::GenePropsOps_Exponential() |
---|
282 | { |
---|
283 | length = new GenePropsOp_Exponential(0.33, 2.0, GeneProps::standard_values.length); |
---|
284 | weight = new GenePropsOp_Exponential(0.5, 2.0, GeneProps::standard_values.weight); |
---|
285 | friction = new GenePropsOp_Exponential(0, 4.0, GeneProps::standard_values.friction); |
---|
286 | curvedness = new GenePropsOp_Exponential(-2, 2, GeneProps::standard_values.curvedness); |
---|
287 | twist = new GenePropsOp_Exponential(-M_PI_2, M_PI_2, GeneProps::standard_values.twist); |
---|
288 | energy = new GenePropsOp_Exponential(0, 10, GeneProps::standard_values.energy); |
---|
289 | |
---|
290 | assimilation = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.assimilation); |
---|
291 | ingestion = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.ingestion); |
---|
292 | stamina = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.stamina); |
---|
293 | muscle_power = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.muscle_power); |
---|
294 | |
---|
295 | cred = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cred); |
---|
296 | cgreen = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cgreen); |
---|
297 | cblue = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cblue); |
---|
298 | } |
---|
299 | |
---|
300 | |
---|
301 | GenePropsOps* GeneProps::standard_ops = NULL; |
---|
302 | GenePropsOps* GeneProps::getStandardOps() |
---|
303 | { |
---|
304 | if (!standard_ops) |
---|
305 | standard_ops = new GenePropsOps_New05(); |
---|
306 | return standard_ops; |
---|
307 | } |
---|