1 /**************************************************************************/
2 /*  Copyright 2012 Tim Day                                                */
3 /*                                                                        */
4 /*  This file is part of Evolvotron                                       */
5 /*                                                                        */
6 /*  Evolvotron is free software: you can redistribute it and/or modify    */
7 /*  it under the terms of the GNU General Public License as published by  */
8 /*  the Free Software Foundation, either version 3 of the License, or     */
9 /*  (at your option) any later version.                                   */
10 /*                                                                        */
11 /*  Evolvotron is distributed in the hope that it will be useful,         */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
14 /*  GNU General Public License for more details.                          */
15 /*                                                                        */
16 /*  You should have received a copy of the GNU General Public License     */
17 /*  along with Evolvotron.  If not, see <http://www.gnu.org/licenses/>.   */
18 /**************************************************************************/
19 
20 /*! \file
21   \brief Implementation of class MutationParameters.
22 */
23 
24 
25 
26 #include "mutation_parameters.h"
27 
28 #include "function_registration.h"
29 #include "function_registry.h"
30 #include "function_constant.h"
31 #include "function_identity.h"
32 #include "function_transform.h"
33 
MutationParameters(uint seed,bool ac,bool debug_mode)34 MutationParameters::MutationParameters(uint seed,bool ac,bool debug_mode)
35   :_function_registry(new FunctionRegistry())
36    ,_r01(seed)
37    ,_r_negexp(seed,1.0)
38    ,_autocool_reset_state(ac)
39    ,_debug_mode(debug_mode)
40 {
41   reset();
42 }
43 
~MutationParameters()44 MutationParameters::~MutationParameters()
45 {}
46 
reset()47 void MutationParameters::reset()
48 {
49   _autocool_enable=_autocool_reset_state;
50   _autocool_halflife=20;
51   _autocool_generations=0;
52 
53   _base_magnitude_parameter_variation=0.25;
54 
55   _base_probability_parameter_reset=0.05;
56   _base_probability_glitch=0.05;
57   _base_probability_shuffle=0.05;
58   _base_probability_insert=0.05;
59   _base_probability_substitute=0.05;
60 
61   _proportion_basic=0.6;
62 
63   _proportion_constant=0.5;
64   _identity_supression=1.0;
65 
66   //! \todo Could do with _max_initial_iterations being higher (64?) for fractal type things but it slows things down too much.
67   _max_initial_iterations=16;
68   _base_probability_iterations_change_step=0.25;
69   _base_probability_iterations_change_jump=0.02;
70 
71   _function_weighting.clear();
72   for (
73        FunctionRegistry::Registrations::const_iterator it=_function_registry->registrations().begin();
74        it!=_function_registry->registrations().end();
75        it++
76        )
77     {
78       if (_debug_mode)
79 	{
80 	  const FunctionRegistration*const fn=
81 #if BOOST_VERSION >= 103400
82 	    it->second;
83 #else
84 	    &*it;
85 #endif
86 	  real initial_weight=(fn->name()=="FunctionNoiseOneChannel" ? 1.0 : 1.0/1024.0);
87 	  _function_weighting.insert(std::make_pair(fn,initial_weight));
88 	}
89       else
90 	{
91 	  real initial_weight=1.0;
92 	  const FunctionRegistration*const fn=
93 #if BOOST_VERSION >= 103400
94 	    it->second;
95 #else
96 	    &*it;
97 #endif
98 	  if (fn->classification() & FnIterative) initial_weight=1.0/1024.0;  // Ouch iterative functions are expensive
99 	  if (fn->classification() & FnFractal) initial_weight=1.0/1024.0;  // Yuk fractals are ugly
100 	  _function_weighting.insert(std::make_pair(fn,initial_weight));
101 	}
102     }
103 
104   recalculate_function_stuff();
105 
106   report_change();
107 }
108 
decay_factor() const109 real MutationParameters::decay_factor() const
110 {
111   assert(_autocool_halflife!=0);
112   return (_autocool_enable ? pow(0.5,_autocool_generations/static_cast<double>(_autocool_halflife)) : 1.0);
113 }
114 
general_cool(real f)115 void MutationParameters::general_cool(real f)
116 {
117   _base_magnitude_parameter_variation*=f;
118 
119   _base_probability_parameter_reset*=f;
120   _base_probability_glitch*=f;
121   _base_probability_shuffle*=f;
122   _base_probability_insert*=f;
123   _base_probability_substitute*=f;
124 
125   _base_probability_iterations_change_step*=f;
126   _base_probability_iterations_change_jump*=f;
127 
128   report_change();
129 }
130 
131 /*! This returns a random bit of image tree.
132   It needs to be capable of generating any sort of node we have.
133   \warning Too much probability of highly branching nodes could result in infinite sized stubs.
134   \todo Compute (statistically) the expected number of nodes in a stub.
135  */
random_function_stub(bool exciting) const136 std::unique_ptr<FunctionNode> MutationParameters::random_function_stub(bool exciting) const
137 {
138   // Base mutations are Constant or Identity types.
139   // (Identity can be Identity or PositionTransformed, proportions depending on identity_supression parameter)
140   const real base=proportion_basic();
141 
142   const real r=(exciting ? base+(1.0-base)*r01() : r01());
143 
144   if (r<(1.0-proportion_constant())*identity_supression()*base)
145     {
146       return FunctionTransform::stubnew(*this,false);
147     }
148   else if (r<(1.0-proportion_constant())*base)
149     {
150       return FunctionIdentity::stubnew(*this,false);
151     }
152   else if (r<base)
153     {
154       return FunctionConstant::stubnew(*this,false);
155     }
156   else
157     {
158       return random_function();
159     }
160 }
161 
random_function() const162 std::unique_ptr<FunctionNode> MutationParameters::random_function() const
163 {
164   const FunctionRegistration* fn_reg=random_weighted_function_registration();
165   return (*(fn_reg->stubnew_fn()))(*this,false);
166 }
167 
random_weighted_function_registration() const168 const FunctionRegistration* MutationParameters::random_weighted_function_registration() const
169 {
170   const real r=r01();
171 
172   const std::map<real,const FunctionRegistration*>::const_iterator it=_function_pick.lower_bound(r);
173 
174   // Just in case last key isn't quite 1.0
175   if (it!=_function_pick.end())
176     {
177       return (*it).second;
178     }
179   else
180     {
181       return (*(_function_pick.rbegin())).second;
182     }
183 }
184 
random_function_branching_ratio() const185 real MutationParameters::random_function_branching_ratio() const
186 {
187   real weighted_args=0.0;
188 
189   for (
190        std::map<const FunctionRegistration*,real>::const_iterator it=_function_weighting.begin();
191        it!=_function_weighting.end();
192        it++
193        )
194     {
195       weighted_args+=(*it).second*(*it).first->args();
196     }
197   return weighted_args/_function_weighting_total;
198 }
199 
change_function_weighting(const FunctionRegistration * fn,real w)200 void MutationParameters::change_function_weighting(const FunctionRegistration* fn,real w)
201 {
202   _function_weighting[fn]=w;
203   recalculate_function_stuff();
204   report_change();
205 }
206 
randomize_function_weightings_for_classifications(uint classification_mask)207 void MutationParameters::randomize_function_weightings_for_classifications(uint classification_mask)
208 {
209   for (
210        std::map<const FunctionRegistration*,real>::iterator it=_function_weighting.begin();
211        it!=_function_weighting.end();
212        it++
213        )
214     {
215       if (classification_mask==0 || classification_mask==static_cast<uint>(-1) || ((*it).first->classification() & classification_mask))
216 	{
217 	  const int i=static_cast<int>(floor(11.0*r01()));
218 	  (*it).second=pow(2,-i);
219 	}
220     }
221 
222   recalculate_function_stuff();
223 
224   report_change();
225 }
226 
get_weighting(const FunctionRegistration * fn)227 real MutationParameters::get_weighting(const FunctionRegistration* fn)
228 {
229   std::map<const FunctionRegistration*,real>::const_iterator it=_function_weighting.find(fn);
230   assert(it!=_function_weighting.end());
231   return (*it).second;
232 }
233 
recalculate_function_stuff()234 void MutationParameters::recalculate_function_stuff()
235 {
236   _function_weighting_total=0.0;
237   for (
238        std::map<const FunctionRegistration*,real>::const_iterator it=_function_weighting.begin();
239        it!=_function_weighting.end();
240        it++
241        )
242     _function_weighting_total+=(*it).second;
243 
244   real normalised=0.0;
245   _function_pick.clear();
246   for (
247        std::map<const FunctionRegistration*,real>::const_iterator it=_function_weighting.begin();
248        it!=_function_weighting.end();
249        it++
250        )
251     {
252       normalised+=(*it).second/_function_weighting_total;
253       _function_pick.insert(std::make_pair(normalised,(*it).first));
254     }
255 }
256 
report_change()257 void MutationParameters::report_change()
258 {}
259 
260