source: cpp/frams/genetics/geneprops.cpp @ 1335

Last change on this file since 1335 was 1335, checked in by Maciej Komosinski, 23 hours ago

Introduced GeneProps::get_standard_values(): a getter function to ensure controlled initialization of the static "standard_values" object

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