Modernized GAlib  3.0.0 current
GAScaling.h
1 // $Header$
2 /* ----------------------------------------------------------------------------
3  scaling.h
4  mbwall 10aug94
5  Copyright (c) 1995 Massachusetts Institute of Technology
6  all rights reserved
7 
8  DESCRIPTION:
9  This is the GAScaling class. It is used to do scaling on a population. When
10 a genome is evaluated, the user's objective function provides an overall
11 rating for each genome. The GA is concerned with fitness, not objective
12 score (unless you do no scaling). So this object is the container for the
13 scaled values.
14  Examples of scaling include linear scaling, sigma truncation, and power law.
15 Goldberg's sharing function is also a type of scaling, and it is implemented
16 here as a unique class.
17  The scaling class is designed to be used with a population. It is stupid -
18 it does know how to update itself, but it must be told when.
19 ---------------------------------------------------------------------------- */
20 #ifndef _ga_scaling_h_
21 #define _ga_scaling_h_
22 
23 #include <GAGenome.h>
24 #include <gaconfig.h>
25 #include <gaid.h>
26 #include <gatypes.h>
27 #include <vector>
28 
29 class GAPopulation;
30 
31 constexpr float gaDefLinearScalingMultiplier = 1.2;
32 constexpr float gaDefSigmaTruncationMultiplier = 2.0;
33 constexpr float gaDefPowerScalingFactor = 1.0005;
34 constexpr float gaDefSharingCutoff = 1.0;
35 
36 /* ----------------------------------------------------------------------------
37 Scaling
38 
39  The scaling object is used to scale the objective scores of a population to
40 avoid clustering and premature convergence (among other things). See golberg
41 for more about the theory. This is basically just a container for any data
42 that the scaling object might need to do its thing. The simplest scalings
43 don't store any data.
44 ---------------------------------------------------------------------------- */
45 class GAScalingScheme : public GAID
46 {
47  public:
48  GADefineIdentity("GAScalingScheme", GAID::Scaling);
49 
50  GAScalingScheme() = default;
51  GAScalingScheme(const GAScalingScheme &s) { copy(s); }
52  GAScalingScheme &operator=(const GAScalingScheme &s)
53  {
54  copy(s);
55  return *this;
56  }
57  ~GAScalingScheme() override = default;
58  virtual GAScalingScheme *clone() const = 0;
59  virtual void copy(const GAScalingScheme &) {}
60  virtual void evaluate(const GAPopulation &p) = 0;
61 };
62 
63 /* ----------------------------------------------------------------------------
64 NoScaling
65 ---------------------------------------------------------------------------- */
67 {
68  public:
69  GADefineIdentity("GANoScaling", GAID::NoScaling);
70 
71  GANoScaling() = default;
72  GANoScaling(const GANoScaling &) = default;
73  GANoScaling &operator=(const GAScalingScheme &) { return *this; }
74  ~GANoScaling() override = default;
75  GAScalingScheme *clone() const override { return new GANoScaling(*this); }
76  void evaluate(const GAPopulation &p) override;
77 };
78 
79 /* ----------------------------------------------------------------------------
80 LinearScaling
81 
82  This scaling object does linear scaling as described in goldberg pp 122-124.
83 ---------------------------------------------------------------------------- */
84 #if USE_LINEAR_SCALING == 1
85 class GALinearScaling : public GAScalingScheme
86 {
87  public:
88  GADefineIdentity("GALinearScaling", GAID::LinearScaling);
89 
90  explicit GALinearScaling(float fm = gaDefLinearScalingMultiplier)
91  {
92  multiplier(fm);
93  }
94  GALinearScaling(const GALinearScaling &arg) : GAScalingScheme(arg) { copy(arg); }
95  GALinearScaling &operator=(const GAScalingScheme &arg)
96  {
97  copy(arg);
98  return (*this);
99  }
100  ~GALinearScaling() override = default;
101  GAScalingScheme *clone() const override
102  {
103  return new GALinearScaling(*this);
104  }
105  void evaluate(const GAPopulation &p) override;
106  void copy(const GAScalingScheme &arg) override
107  {
108  if (&arg != this)
109  {
110  GAScalingScheme::copy(arg);
111  c = (DYN_CAST(const GALinearScaling &, arg)).c;
112  }
113  }
114 
115  float multiplier(float fm);
116  float multiplier() const { return c; }
117 
118  protected:
119  float c; // linear scaling multiplier
120 };
121 #endif
122 
123 /* ----------------------------------------------------------------------------
124 SigmaTruncationScaling
125 
126  This scaling object does sigma truncation as defined in goldberg p124.
127 ---------------------------------------------------------------------------- */
128 #if USE_SIGMA_TRUNC_SCALING == 1
129 class GASigmaTruncationScaling : public GAScalingScheme
130 {
131  public:
132  GADefineIdentity("GASigmaTruncationScaling", GAID::SigmaTruncationScaling);
133 
134  explicit GASigmaTruncationScaling(float m = gaDefSigmaTruncationMultiplier)
135  {
136  multiplier(m);
137  }
138  GASigmaTruncationScaling(const GASigmaTruncationScaling &arg)
139  : GAScalingScheme(arg)
140  {
141  copy(arg);
142  }
143  GASigmaTruncationScaling &operator=(const GAScalingScheme &arg)
144  {
145  copy(arg);
146  return (*this);
147  }
148  ~GASigmaTruncationScaling() override = default;
149  GAScalingScheme *clone() const override
150  {
151  return new GASigmaTruncationScaling(*this);
152  }
153  void evaluate(const GAPopulation &p) override;
154  void copy(const GAScalingScheme &arg) override
155  {
156  if (&arg != this)
157  {
158  GAScalingScheme::copy(arg);
159  c = (DYN_CAST(const GASigmaTruncationScaling &, arg)).c;
160  }
161  }
162 
163  float multiplier(float fm);
164  float multiplier() const { return c; }
165 
166  protected:
167  float c; // std deviation multiplier
168 };
169 #endif
170 
171 /* ----------------------------------------------------------------------------
172 PowerLawScaling
173 
174  This scaling object does power law scaling as defined in goldberg p124.
175 ---------------------------------------------------------------------------- */
176 #if USE_POWER_LAW_SCALING == 1
177 class GAPowerLawScaling : public GAScalingScheme
178 {
179  public:
180  GADefineIdentity("GAPowerLawScaling", GAID::PowerLawScaling);
181 
182  explicit GAPowerLawScaling(float f = gaDefPowerScalingFactor) { k = f; }
183  GAPowerLawScaling(const GAPowerLawScaling &arg) : GAScalingScheme(arg)
184  {
185  copy(arg);
186  }
187  GAPowerLawScaling &operator=(const GAScalingScheme &arg)
188  {
189  copy(arg);
190  return (*this);
191  }
192  ~GAPowerLawScaling() override = default;
193  GAScalingScheme *clone() const override
194  {
195  return new GAPowerLawScaling(*this);
196  }
197  void evaluate(const GAPopulation &p) override;
198  void copy(const GAScalingScheme &arg) override
199  {
200  if (&arg != this)
201  {
202  GAScalingScheme::copy(arg);
203  k = (DYN_CAST(const GAPowerLawScaling &, arg)).k;
204  }
205  }
206 
207  float power(float p) { return k = p; }
208  float power() const { return k; }
209 
210  protected:
211  float k; // power scaling factor
212 };
213 #endif
214 
215 /* ----------------------------------------------------------------------------
216 Sharing
217 
218  This scaling object does sharing as described in goldberg p 192. This
219 implementation does triangular sharing with the (optional) alpha parameter for
220 changing the curvature of the sharing range and the (required) sigma parameter
221 for controlling the range of influence. If you want a different type of
222 sharing function, then derive from this class and define a new (virtual)
223 evaluate method and add whatever member data you need to specify the shape
224 of your sharing function.
225  We use the distance function to scale the objective scores of the
226 genomes so that if there are many similar genomes in a population
227 their scores will be decreased, thus giving sub-species a greater chance to
228 reproduce.
229  This sharing function is defined as follows:
230 
231  /
232  | 1 - (d(i,j)/sigma) ^ alpha d(i,j) < sigma
233  s(d(i,j)) = |
234  | 0 d(i,j) >= sigma
235  \
236 
237  where d is the distance between any two individuals and is defined such
238 that d(i,j) = 0 means that individuals i and j are identical. d() has no
239 upper bound, but it is never negative.
240  The alpha controls the shape of the sharing function. When alpha=1 then
241 the 'curve' is a straight line. If alpha is < 1 then the curves are concave,
242 if alpha is > 1 then the curves are convex.
243  If you decide to use this type of sharing, be careful of the sigma value
244 that you use. It can make a HUGE difference, depending upon the objective.
245  Distance functions are independent of the sharing functions (as defined in
246 Goldberg, that is).
247  A similarity (distance) function is used with the sharing object. It is a
248 type of speciation (similar in functionality to DeJong crowding, but this uses
249 fitness scaling rather than replacement strategy to affect the speciation).
250 If the genomes are identical, the similarity function should return a value of
251 0.0, if completely different then return a value of 1.0. 0 means less
252 diversity means all genomes are the same.
253  You can specify whether the scaling should be maximize or minimize based.
254 If you are maximizing, the scaling will divide the raw score by the scaling
255 factor. If you are minimizing, the scaling will multiply the score by the
256 scaling factor. (By definition, the scaling factor will always be >= 1.0)
257  By default, the scaling object uses the max/min settings that it contains
258 (so you can set the scaling independently of the GA). If the scaling's min/max
259 was not set, then it tries to use the min/max settings in the GA that owns
260 the population to which the scaling object is attached. If there is no GA,
261 then it bases its min/max on the sort order of the population.
262  You can set the minimaxi to:
263 
264  GA::MINIMIZE - scale by multiplying the raw scores
265  GA::MAXIMIZE - scale by dividing the raw scores
266  0 - minimize or maximize based upon the GA's settings
267 
268 *** This should be called TriangularSharing rather than simply Sharing.
269 ---------------------------------------------------------------------------- */
270 #if USE_SHARING == 1
271 class GASharing : public GAScalingScheme
272 {
273  public:
274  GADefineIdentity("GASharing", GAID::Sharing);
275 
276  explicit GASharing(GAGenome::Comparator func, float cut = gaDefSharingCutoff,
277  float a = 1.0)
278  {
279  N = 0;
280  df = func;
281  _sigma = cut;
282  _alpha = a;
283  _minmax = 0;
284  }
285  explicit GASharing(float cut = gaDefSharingCutoff, float a = 1.0) :
286  df(nullptr)
287  {
288  N = 0;
289  _sigma = cut;
290  _alpha = a;
291  _minmax = 0;
292  }
293  GASharing(const GASharing &arg) : GAScalingScheme(arg)
294  {
295  N = 0;
296  copy(arg);
297  }
298  GASharing &operator=(const GAScalingScheme &arg)
299  {
300  copy(arg);
301  return (*this);
302  }
303  ~GASharing() override = default;
304  GAScalingScheme *clone() const override { return new GASharing(*this); }
305  void copy(const GAScalingScheme &arg) override;
306  void evaluate(const GAPopulation &p) override;
307 
308  GAGenome::Comparator distanceFunction(GAGenome::Comparator f)
309  {
310  return df = f;
311  }
312  GAGenome::Comparator distanceFunction() const { return df; }
313 
314  float sigma(float);
315  float sigma() const { return _sigma; }
316 
317  float alpha(float c) { return _alpha = c; }
318  float alpha() const { return _alpha; }
319 
320  int minimaxi(int i);
321  int minimaxi() const { return _minmax; }
322 
323  protected:
324  GAGenome::Comparator df; // the user-defined distance function
325  unsigned int N; // how many do we have? (n of n-by-n)
326  std::vector<float> d; // the distances for each genome pair
327  float _sigma; // absolute cutoff from central point
328  float _alpha; // controls the curvature of sharing f
329  int _minmax; // should we minimize or maximize?
330 };
331 #endif
332 
333 #endif
This defines the identifiers for polymorphic classes.
Definition: gaid.h:20
Definition: GAScaling.h:67
Definition: GAPopulation.h:66
Definition: GAScaling.h:46