line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::ES; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require 5.005_62; |
4
|
1
|
|
|
1
|
|
777
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
27
|
|
6
|
1
|
|
|
1
|
|
702
|
use FileHandle; |
|
1
|
|
|
|
|
18518
|
|
|
1
|
|
|
|
|
7
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
1458
|
use Math::Random qw( random_permuted_index ); |
|
1
|
|
|
|
|
8238
|
|
|
1
|
|
|
|
|
8688
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
require Exporter; |
11
|
|
|
|
|
|
|
# use AutoLoader qw(AUTOLOAD); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our %EXPORT_TAGS = (); |
16
|
|
|
|
|
|
|
our @EXPORT_OK = (); |
17
|
|
|
|
|
|
|
our @EXPORT = (); |
18
|
|
|
|
|
|
|
our $VERSION = '0.08'; # Change version number in POD ! |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $debug = 0; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# |
25
|
|
|
|
|
|
|
# Selection schemes: |
26
|
|
|
|
|
|
|
# 1 : n best survive |
27
|
|
|
|
|
|
|
# 2 : n-1 best survive, last choses randomly |
28
|
|
|
|
|
|
|
# 3 : GA Roulette (not implemented, yet) |
29
|
|
|
|
|
|
|
# |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Package variable |
32
|
|
|
|
|
|
|
my $count = 0; |
33
|
|
|
|
|
|
|
my $file = 'es'; |
34
|
|
|
|
|
|
|
my $debug_suffix = '.dbg'; |
35
|
|
|
|
|
|
|
my $log_suffix = '.log'; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
39
|
|
|
|
|
|
|
# |
40
|
|
|
|
|
|
|
# Constructor method |
41
|
|
|
|
|
|
|
# |
42
|
|
|
|
|
|
|
sub new { |
43
|
|
|
|
|
|
|
|
44
|
3
|
|
|
3
|
0
|
9823
|
my $obj = shift; |
45
|
|
|
|
|
|
|
|
46
|
3
|
|
|
|
|
10
|
$count++; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Preset with default values |
49
|
3
|
|
|
|
|
38
|
my $eso = bless { |
50
|
|
|
|
|
|
|
'populations' => 2, |
51
|
|
|
|
|
|
|
'individuals' => 5, |
52
|
|
|
|
|
|
|
'parents' => 2, |
53
|
|
|
|
|
|
|
'children' => 10, |
54
|
|
|
|
|
|
|
'elite' => 1, |
55
|
|
|
|
|
|
|
'selection_scheme' => 1, |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
'generations' => 50, |
58
|
|
|
|
|
|
|
'stepwidth_const' => 1, |
59
|
|
|
|
|
|
|
'stepwidth_var' => 1.5, |
60
|
|
|
|
|
|
|
'variance_mutator' => 0.5, |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
'isolation' => 25, |
63
|
|
|
|
|
|
|
'migrators' => 1, |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
'genes' => [], |
66
|
|
|
|
|
|
|
'gene_deviations' => [], |
67
|
|
|
|
|
|
|
'max_gene_values' => [], |
68
|
|
|
|
|
|
|
'min_gene_values' => [], |
69
|
|
|
|
|
|
|
'rating_function' => '', |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
'log' => 1, |
72
|
|
|
|
|
|
|
'debug' => 0, |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
'log_handle' => FileHandle->new(), |
75
|
|
|
|
|
|
|
'debug_handle' => FileHandle->new(), |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
'log_file' => "$file-$count$log_suffix", |
78
|
|
|
|
|
|
|
'debug_file' => "$file-$count$debug_suffix", |
79
|
|
|
|
|
|
|
}, $obj; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Overwrite with user specific values |
82
|
3
|
50
|
|
|
|
303
|
$eso->set_values(@_) if (@_); |
83
|
3
|
|
|
|
|
11
|
return $eso; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
87
|
|
|
|
|
|
|
# |
88
|
|
|
|
|
|
|
# Add user specific values |
89
|
|
|
|
|
|
|
# |
90
|
|
|
|
|
|
|
sub set_values { |
91
|
3
|
|
|
3
|
1
|
5
|
my $obj = shift; |
92
|
|
|
|
|
|
|
# Add or overwrite |
93
|
3
|
|
|
|
|
7
|
%{$obj} = ((%{$obj}) ,@_); |
|
3
|
|
|
|
|
75
|
|
|
3
|
|
|
|
|
50
|
|
94
|
3
|
|
|
|
|
25
|
return ($obj); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
# Validate control parameters, array conformities etc. |
101
|
|
|
|
|
|
|
# |
102
|
|
|
|
|
|
|
sub validate { |
103
|
14
|
|
|
14
|
1
|
30
|
my $obj = shift; |
104
|
|
|
|
|
|
|
|
105
|
14
|
|
|
|
|
22
|
my $msg = ''; |
106
|
|
|
|
|
|
|
|
107
|
14
|
50
|
|
|
|
56
|
$msg .= " Number of populations must be greater than zero\n" if ($obj->{'populations'} < 1); |
108
|
14
|
50
|
|
|
|
193
|
$msg .= " Number of individuals must be greater than zero\n" if ($obj->{'individuals'} < 1); |
109
|
14
|
50
|
|
|
|
42
|
$msg .= " Number of parents must be greater than zero\n" if ($obj->{'parents'} < 1); |
110
|
14
|
50
|
|
|
|
46
|
$msg .= " Number of children must be greater than zero\n" if ($obj->{'children'} < 1); |
111
|
14
|
50
|
|
|
|
45
|
$msg .= " Number of children must be greater than or equal to number of individuals\n" |
112
|
|
|
|
|
|
|
if ($obj->{'children'} < $obj->{'individuals'}); |
113
|
14
|
50
|
|
|
|
53
|
$msg .= " Number of elite must be less than number of individuals\n" |
114
|
|
|
|
|
|
|
if ($obj->{'elite'} >= $obj->{'individuals'}); |
115
|
14
|
50
|
66
|
|
|
62
|
$msg .= " Selection scheme must be 1 or 2\n" if ($obj->{'selection_scheme'} != 1 and |
116
|
|
|
|
|
|
|
$obj->{'selection_scheme'} != 2); |
117
|
14
|
50
|
|
|
|
44
|
$msg .= " Number of generations must be greater than zero\n" if ($obj->{'generations'} < 1); |
118
|
14
|
50
|
|
|
|
41
|
$msg .= " variance_mutator must be positive\n" if ($obj->{'variance_mutator'} < 0); |
119
|
14
|
50
|
|
|
|
47
|
$msg .= " Number of isolation cycles must not be negative\n" if ($obj->{'isolation'} < 0); |
120
|
14
|
50
|
|
|
|
49
|
$msg .= " Number of migrators must not be negative\n" if ($obj->{'migrators'} < 0); |
121
|
|
|
|
|
|
|
|
122
|
14
|
|
|
|
|
21
|
my $ng = @{$obj->{'genes'}}; |
|
14
|
|
|
|
|
29
|
|
123
|
14
|
|
|
|
|
20
|
my $ngd = @{$obj->{'gene_deviations'}}; |
|
14
|
|
|
|
|
25
|
|
124
|
14
|
|
|
|
|
17
|
my $gmx = @{$obj->{'max_gene_values'}}; |
|
14
|
|
|
|
|
23
|
|
125
|
14
|
|
|
|
|
19
|
my $gmn = @{$obj->{'min_gene_values'}}; |
|
14
|
|
|
|
|
23
|
|
126
|
|
|
|
|
|
|
|
127
|
14
|
50
|
|
|
|
42
|
$msg .= " Number of gene_deviations ($ngd) must be equal to number of genes ($ng)\n" |
128
|
|
|
|
|
|
|
unless ($ng == $ngd); |
129
|
14
|
50
|
|
|
|
33
|
$msg .= " Number of max_gene_values ($gmx) must be equal to number of genes ($ng)\n" |
130
|
|
|
|
|
|
|
unless ($ng == $gmx); |
131
|
14
|
50
|
|
|
|
642
|
$msg .= " Number of min_gene_values ($gmn) must be equal to number of genes ($ng)\n" |
132
|
|
|
|
|
|
|
unless ($ng == $gmn); |
133
|
|
|
|
|
|
|
|
134
|
14
|
|
|
|
|
52
|
for my $i (1..$ng) { |
135
|
86
|
|
|
|
|
151
|
my $g = $obj->{'genes'}[$i-1]; |
136
|
86
|
|
|
|
|
271
|
my $max = $obj->{'max_gene_values'}[$i-1]; |
137
|
86
|
|
|
|
|
143
|
my $min = $obj->{'min_gene_values'}[$i-1]; |
138
|
86
|
50
|
33
|
|
|
329
|
$msg .= " max_gene_value $i ($max) is smaller than gene $i ($g)\n" |
139
|
|
|
|
|
|
|
if ($ng == $gmx and $max < $g ); |
140
|
86
|
50
|
33
|
|
|
352
|
$msg .= " min_gene_value $i ($min) is greater than gene $i ($g)\n" |
141
|
|
|
|
|
|
|
if ($ng == $gmn and $min > $g ); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
14
|
100
|
|
|
|
105
|
if ($obj->{'populations'} == 1) { |
145
|
2
|
50
|
|
|
|
9
|
$msg .= " Isolation feature cannot be used for a single population\n" |
146
|
|
|
|
|
|
|
if ($obj->{'isolation'} > 0); |
147
|
2
|
50
|
|
|
|
8
|
$msg .= " Migration feature cannot be used for a single population\n" |
148
|
|
|
|
|
|
|
if ($obj->{'migrators'} > 0); |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
14
|
50
|
|
|
|
107
|
$msg .= " Rating function is missing\n" |
152
|
|
|
|
|
|
|
unless (ref($obj->{'rating_function'}) =~ /CODE/); |
153
|
|
|
|
|
|
|
|
154
|
14
|
50
|
|
|
|
31
|
print "Validated\n" if ($debug); |
155
|
14
|
|
|
|
|
37
|
return ($msg); |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
159
|
|
|
|
|
|
|
# |
160
|
|
|
|
|
|
|
# go Darwin go |
161
|
|
|
|
|
|
|
# |
162
|
|
|
|
|
|
|
sub start { |
163
|
|
|
|
|
|
|
|
164
|
3
|
|
|
3
|
1
|
17
|
my $obj = shift; |
165
|
|
|
|
|
|
|
|
166
|
3
|
|
|
|
|
7
|
my $debug = $obj->{'debug'}; |
167
|
3
|
|
|
|
|
8
|
my $log = $obj->{'log'}; |
168
|
3
|
|
|
|
|
10
|
$| = 1; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Validate |
171
|
3
|
|
|
|
|
16
|
my $msg = $obj->validate(); |
172
|
3
|
50
|
|
|
|
10
|
return ($msg) if ($msg); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Files |
175
|
3
|
|
|
|
|
7
|
my $dfh = $obj->{'debug_handle'}; |
176
|
3
|
|
|
|
|
8
|
my $lfh = $obj->{'log_handle'}; |
177
|
3
|
50
|
|
|
|
10
|
if ($debug) { |
178
|
0
|
|
|
|
|
0
|
open ($dfh, ">".$obj->{'debug_file'}); |
179
|
|
|
|
|
|
|
} |
180
|
3
|
50
|
|
|
|
7
|
if ($log) { |
181
|
3
|
|
|
|
|
87647
|
open ($lfh, ">".$obj->{'log_file'}); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# Setup |
185
|
3
|
|
|
|
|
19
|
my $npop = $obj->{'populations'}; |
186
|
3
|
|
|
|
|
11
|
my @populations = (); |
187
|
3
|
|
|
|
|
17
|
for (my $i=1; $i<=$npop; $i++) { |
188
|
8
|
50
|
|
|
|
17
|
print $dfh "Creating population number $i ...\n" if ($debug); |
189
|
8
|
|
|
|
|
38
|
my $pop = Math::ES::Population->new ( |
190
|
|
|
|
|
|
|
'individuals' => $obj->{'individuals'}, |
191
|
|
|
|
|
|
|
'parents' => $obj->{'parents'}, |
192
|
|
|
|
|
|
|
'children' => $obj->{'children'}, |
193
|
|
|
|
|
|
|
'elite' => $obj->{'elite'}, |
194
|
|
|
|
|
|
|
'selection_scheme' => $obj->{'selection_scheme'}, |
195
|
|
|
|
|
|
|
'migrators' => $obj->{'migrators'}, |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
'stepwidth_const' => $obj->{'stepwidth_const'}, |
198
|
|
|
|
|
|
|
'stepwidth_var' => $obj->{'stepwidth_var'}, |
199
|
|
|
|
|
|
|
'variance_mutator' => $obj->{'variance_mutator'}, |
200
|
|
|
|
|
|
|
|
201
|
8
|
|
|
|
|
29
|
'genes' => [@{$obj->{'genes'}}], |
202
|
8
|
|
|
|
|
26
|
'max_gene_values' => [@{$obj->{'max_gene_values'}}], |
203
|
8
|
|
|
|
|
109
|
'min_gene_values' => [@{$obj->{'min_gene_values'}}], |
204
|
0
|
|
|
|
|
0
|
'gene_deviations' => [@{$obj->{'gene_deviations'}}], |
205
|
|
|
|
|
|
|
'max_gene_deviations' => |
206
|
0
|
|
|
|
|
0
|
( defined($obj->{'max_gene_deviations'}) ? [@{$obj->{'max_gene_deviations'}}] : [ ] ), |
207
|
|
|
|
|
|
|
'min_gene_deviations' => |
208
|
8
|
50
|
|
|
|
42
|
( defined($obj->{'min_gene_deviations'}) ? [@{$obj->{'min_gene_deviations'}}] : [ ] ), |
|
|
50
|
|
|
|
|
|
209
|
|
|
|
|
|
|
'rating_function' => $obj->{'rating_function'}, |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
'debug' => $obj->{'debug'}, |
212
|
|
|
|
|
|
|
'debug_handle' => $obj->{'debug_handle'}, |
213
|
|
|
|
|
|
|
); |
214
|
8
|
|
|
|
|
21
|
push (@populations, $pop); |
215
|
8
|
50
|
|
|
|
31
|
print $dfh "done\n" if ($debug); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
3
|
|
|
|
|
12
|
$obj->{'populations_list'} = [@populations]; |
219
|
|
|
|
|
|
|
|
220
|
3
|
|
|
|
|
11
|
$obj->run; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
224
|
|
|
|
|
|
|
# |
225
|
|
|
|
|
|
|
# go Darwin go |
226
|
|
|
|
|
|
|
# |
227
|
|
|
|
|
|
|
sub run { |
228
|
11
|
|
|
11
|
1
|
172
|
my $obj = shift; |
229
|
|
|
|
|
|
|
|
230
|
11
|
|
|
|
|
26
|
my $debug = $obj->{'debug'}; |
231
|
11
|
|
|
|
|
23
|
my $log = $obj->{'log'}; |
232
|
11
|
|
|
|
|
17
|
my $dfh = $obj->{'debug_handle'}; |
233
|
11
|
|
|
|
|
26
|
my $lfh = $obj->{'log_handle'}; |
234
|
|
|
|
|
|
|
# $| = 1; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# 0, Validate |
237
|
11
|
|
|
|
|
42
|
my $msg = $obj->validate(); |
238
|
11
|
50
|
|
|
|
29
|
return ($msg) if ($msg); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# 1, Setup |
241
|
11
|
|
|
|
|
15
|
my @populations = @{$obj->{'populations_list'}}; |
|
11
|
|
|
|
|
34
|
|
242
|
11
|
|
|
|
|
15
|
my $nmig = $obj->{'migrators'}; |
243
|
11
|
|
|
|
|
24
|
my $niso = $obj->{'isolation'}; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# 2, Evaluate first generation |
246
|
11
|
|
|
|
|
24
|
my @pop_rate_list; |
247
|
|
|
|
|
|
|
my @pop_rate_ranked; |
248
|
11
|
|
|
|
|
19
|
foreach my $pop (@populations) { |
249
|
|
|
|
|
|
|
# Evaluate function |
250
|
40
|
|
|
|
|
81
|
push (@pop_rate_list, $pop->rate_individuals()); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Sort individuals |
253
|
40
|
|
|
|
|
90
|
push (@pop_rate_ranked, $pop->rank_individuals()); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# --- Loop |
258
|
11
|
|
|
|
|
26
|
my $maxgn = $obj->{'generations'}; |
259
|
11
|
|
|
|
|
33
|
for (my $gn = 1; $gn <= $maxgn; $gn++) { |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# This should go to log file |
262
|
520
|
50
|
|
|
|
1382
|
if ($log) { |
263
|
520
|
|
|
|
|
2483
|
print $lfh ">>","-"x80,"\n"; |
264
|
520
|
|
|
|
|
1399
|
print $lfh ">>Generation $gn\n"; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# 3, Create children |
268
|
520
|
|
|
|
|
926
|
foreach my $pop (@populations) { |
269
|
1380
|
|
|
|
|
4654
|
$pop->manage_children(); |
270
|
|
|
|
|
|
|
|
271
|
1380
|
|
|
|
|
5803
|
$pop->do_selection(); |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
1380
|
50
|
|
|
|
4182
|
if ($log) { |
275
|
1380
|
|
|
|
|
4415
|
my $ra_p= $pop->rank_individuals(); |
276
|
1380
|
|
|
|
|
7061
|
print $lfh " Ranking list:\t"; |
277
|
1380
|
|
|
|
|
2997
|
foreach my $p (@$ra_p) { |
278
|
9400
|
|
|
|
|
60054
|
printf $lfh " %10.5f", $p; |
279
|
|
|
|
|
|
|
} |
280
|
1380
|
|
|
|
|
7259
|
print $lfh "\tBest genes: ",$pop->{'individuals_list'}[0]->pretty_genes; |
281
|
1380
|
|
|
|
|
6417
|
print $lfh "\n"; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# 4, Do migration |
287
|
520
|
100
|
66
|
|
|
2482
|
if ($nmig > 0 and scalar(@populations) > 1 ) { |
288
|
100
|
|
|
|
|
495
|
$obj->do_migration(); |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# Do mixing |
292
|
520
|
100
|
66
|
|
|
6996
|
if ($niso > 0 and scalar(@populations) > 1 and ($gn % $niso) == 0) { |
|
|
|
100
|
|
|
|
|
293
|
3
|
|
|
|
|
15
|
$obj->do_mixing(); |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
11
|
|
|
|
|
66
|
return ($obj->return_best_value(), [$obj->return_best_genes()]); |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
303
|
|
|
|
|
|
|
# |
304
|
|
|
|
|
|
|
# Do migration of n individuals |
305
|
|
|
|
|
|
|
# |
306
|
|
|
|
|
|
|
sub do_migration { |
307
|
100
|
|
|
100
|
0
|
141
|
my $obj = shift; |
308
|
|
|
|
|
|
|
|
309
|
100
|
|
|
|
|
282
|
my $debug = $obj->{'debug'}; |
310
|
100
|
|
|
|
|
201
|
my $dfh = $obj->{'debug_handle'}; |
311
|
100
|
|
|
|
|
185
|
my $nmig = $obj->{'migrators'}; |
312
|
100
|
|
|
|
|
134
|
my @populations = @{$obj->{'populations_list'}}; |
|
100
|
|
|
|
|
355
|
|
313
|
|
|
|
|
|
|
|
314
|
100
|
|
|
|
|
426
|
for my $i (1..$nmig) { |
315
|
|
|
|
|
|
|
|
316
|
200
|
|
|
|
|
337
|
my @migrators = (); |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Fetch migrator |
319
|
200
|
|
|
|
|
395
|
foreach my $pop (@populations) { |
320
|
600
|
|
|
|
|
1641
|
push (@migrators, $pop->withdraw_random_individual()); |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Insert migrator (cyclic changed) |
324
|
200
|
|
|
|
|
339
|
my $p = shift (@populations); push (@populations, $p); |
|
200
|
|
|
|
|
308
|
|
325
|
200
|
|
|
|
|
342
|
foreach my $pop (@populations) { |
326
|
600
|
|
|
|
|
11923
|
$pop->integrate_individual( shift(@migrators) ); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Debug |
331
|
100
|
50
|
|
|
|
396
|
print $dfh "Migrated $nmig individual(s)\n" if ($debug); |
332
|
|
|
|
|
|
|
|
333
|
100
|
|
|
|
|
281
|
return (1); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
338
|
|
|
|
|
|
|
# |
339
|
|
|
|
|
|
|
# Do mixing of all populations after n generations of isolation |
340
|
|
|
|
|
|
|
# |
341
|
|
|
|
|
|
|
sub do_mixing { |
342
|
3
|
|
|
3
|
0
|
7
|
my $obj = shift; |
343
|
|
|
|
|
|
|
|
344
|
3
|
|
|
|
|
7
|
my @all_indy = (); |
345
|
3
|
|
|
|
|
8
|
my @idx = (); |
346
|
3
|
|
|
|
|
6
|
my @nindy = (); |
347
|
|
|
|
|
|
|
|
348
|
3
|
|
|
|
|
7
|
my $debug = $obj->{'debug'}; |
349
|
3
|
|
|
|
|
7
|
my $dfh = $obj->{'debug_handle'}; |
350
|
3
|
|
|
|
|
7
|
my $niso = $obj->{'isolation'}; |
351
|
3
|
|
|
|
|
4
|
my @populations = @{$obj->{'populations_list'}}; |
|
3
|
|
|
|
|
12
|
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Empty all populations |
354
|
3
|
|
|
|
|
6
|
foreach my $pop (@populations) { |
355
|
10
|
|
|
|
|
17
|
my $n1 = $pop->{'individuals'}; |
356
|
10
|
50
|
|
|
|
27
|
print $dfh "\t$n1 individuals in current pop\n" if ($debug); |
357
|
10
|
|
|
|
|
26
|
push (@all_indy, $pop->withdraw_all_individual); |
358
|
10
|
|
|
|
|
28
|
push (@nindy, $n1); |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
3
|
50
|
|
|
|
13
|
print $dfh "\t",scalar(@all_indy)," individuals in total\n" if ($debug); |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Now fill again ... |
364
|
3
|
|
|
|
|
5
|
my $n2 = scalar (@all_indy); |
365
|
3
|
|
|
|
|
16
|
@idx = &random_permuted_index($n2); |
366
|
|
|
|
|
|
|
|
367
|
3
|
50
|
|
|
|
209
|
print $dfh " Indexvector : \n",join(":",@idx),"\n" if ($debug); |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# ... all populations ... |
370
|
3
|
|
|
|
|
7
|
foreach my $pop (@populations) { |
371
|
10
|
|
|
|
|
15
|
my $n1 = shift(@nindy); |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# ... with randomly choosen individuals. |
374
|
10
|
|
|
|
|
23
|
for my $i (1..$n1) { |
375
|
80
|
|
|
|
|
109
|
my $idx = shift(@idx); |
376
|
80
|
50
|
33
|
|
|
363
|
if (defined($idx) and defined($all_indy[$idx])) { |
377
|
80
|
|
|
|
|
182
|
$pop->integrate_individual( $all_indy[$idx] ); |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
else { |
380
|
0
|
|
|
|
|
0
|
print $dfh " Oops, we lost an individual: $i from $n1\n"; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
# Debug |
386
|
3
|
50
|
|
|
|
11
|
print $dfh "Mixing done\n" if ($debug); |
387
|
|
|
|
|
|
|
|
388
|
3
|
|
|
|
|
27
|
return (1); |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
393
|
|
|
|
|
|
|
# |
394
|
|
|
|
|
|
|
# Retrieve best genes from all populations |
395
|
|
|
|
|
|
|
# |
396
|
|
|
|
|
|
|
sub return_best_genes { |
397
|
21
|
|
|
21
|
1
|
539
|
my $obj = shift; |
398
|
|
|
|
|
|
|
|
399
|
21
|
|
|
|
|
29
|
my @populations = @{$obj->{'populations_list'}}; |
|
21
|
|
|
|
|
63
|
|
400
|
|
|
|
|
|
|
|
401
|
21
|
|
|
|
|
33
|
my @best_indys = (); |
402
|
21
|
|
|
|
|
36
|
foreach my $pop (@populations) { |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Be sure, that we have an ordered list. |
405
|
76
|
|
|
|
|
147
|
$pop->rank_individuals(); |
406
|
|
|
|
|
|
|
|
407
|
76
|
|
|
|
|
196
|
push (@best_indys, $pop->{'individuals_list'}[0]); |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
21
|
|
|
|
|
86
|
@best_indys = sort { $a->rate() <=> $b->rate() } (@best_indys); |
|
87
|
|
|
|
|
192
|
|
411
|
|
|
|
|
|
|
|
412
|
21
|
|
|
|
|
33
|
return (@{$best_indys[0]{'genes'}}); |
|
21
|
|
|
|
|
221
|
|
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
416
|
|
|
|
|
|
|
# |
417
|
|
|
|
|
|
|
# Retrieve best function value from all populations |
418
|
|
|
|
|
|
|
# |
419
|
|
|
|
|
|
|
sub return_best_value { |
420
|
21
|
|
|
21
|
1
|
59
|
my $obj = shift; |
421
|
|
|
|
|
|
|
|
422
|
21
|
|
|
|
|
53
|
my @populations = @{$obj->{'populations_list'}}; |
|
21
|
|
|
|
|
69
|
|
423
|
|
|
|
|
|
|
|
424
|
21
|
|
|
|
|
40
|
my @best_indys = (); |
425
|
21
|
|
|
|
|
42
|
foreach my $pop (@populations) { |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# Be sure, that we have an ordered list. |
428
|
76
|
|
|
|
|
141
|
$pop->rank_individuals(); |
429
|
|
|
|
|
|
|
|
430
|
76
|
|
|
|
|
199
|
push (@best_indys, $pop->{'individuals_list'}[0]); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
21
|
|
|
|
|
74
|
@best_indys = sort { $a->rate() <=> $b->rate() } (@best_indys); |
|
87
|
|
|
|
|
168
|
|
434
|
|
|
|
|
|
|
|
435
|
21
|
|
|
|
|
55
|
return ($best_indys[0]->rate); |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
439
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
package Math::ES::Population; |
442
|
1
|
|
|
1
|
|
23
|
use Math::Random qw( random_uniform_integer ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1840
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub new { |
445
|
8
|
|
|
8
|
|
16
|
my $name = shift; |
446
|
8
|
|
|
|
|
202
|
my $obj = bless {@_}, $name; |
447
|
|
|
|
|
|
|
|
448
|
8
|
|
|
|
|
23
|
my $debug = $obj->{'debug'}; |
449
|
8
|
|
|
|
|
14
|
my $dfh = $obj->{'debug_handle'}; |
450
|
|
|
|
|
|
|
|
451
|
8
|
|
|
|
|
14
|
my $nindiv = $obj->{'individuals'}; |
452
|
8
|
|
|
|
|
14
|
$obj->{'pop_counter'} = 0; |
453
|
|
|
|
|
|
|
|
454
|
8
|
50
|
|
|
|
21
|
print $dfh " Creating population with $nindiv members\n" if ($debug); |
455
|
|
|
|
|
|
|
|
456
|
8
|
|
|
|
|
12
|
my @individuals = (); |
457
|
8
|
|
|
|
|
21
|
for (my $j=1; $j <= $nindiv; $j++) { |
458
|
60
|
50
|
|
|
|
111
|
print $dfh "\tCreating individuum $j out of $nindiv ... " if ($debug); |
459
|
|
|
|
|
|
|
# Guarantee a individual with the input genes |
460
|
60
|
|
|
|
|
69
|
my $do_mutate = 1; |
461
|
60
|
100
|
|
|
|
112
|
$do_mutate = 0 if ($j == 1); |
462
|
60
|
|
|
|
|
188
|
my $indi = Math::ES::Individuum->new ( |
463
|
|
|
|
|
|
|
'pop_rate_individuals' => undef, |
464
|
60
|
|
|
|
|
398
|
'genes' => [@{$obj->{'genes'}}], |
465
|
60
|
|
|
|
|
160
|
'gene_deviations' => [@{$obj->{'gene_deviations'}}], |
466
|
60
|
|
|
|
|
342
|
'max_gene_values' => [@{$obj->{'max_gene_values'}}], |
467
|
60
|
|
|
|
|
78
|
'min_gene_values' => [@{$obj->{'min_gene_values'}}], |
468
|
|
|
|
|
|
|
'rating_function' => $obj->{'rating_function'}, |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
'stepwidth_const' => $obj->{'stepwidth_const'}, |
471
|
|
|
|
|
|
|
'stepwidth_var' => $obj->{'stepwidth_var'}, |
472
|
|
|
|
|
|
|
'variance_mutator' => $obj->{'variance_mutator'}, |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
'mutate' => $do_mutate, |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
'debug' => $obj->{'debug'}, |
477
|
|
|
|
|
|
|
); |
478
|
60
|
|
|
|
|
138
|
push (@individuals, $indi); |
479
|
60
|
50
|
|
|
|
197
|
print $dfh " ok\n" if ($debug); |
480
|
|
|
|
|
|
|
} |
481
|
8
|
|
|
|
|
31
|
$obj->{'individuals_list'} = [@individuals]; |
482
|
8
|
50
|
|
|
|
21
|
print $dfh " done\n" if ($debug); |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# --- |
485
|
|
|
|
|
|
|
|
486
|
8
|
|
|
|
|
25
|
return $obj; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# ------------- |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
# Create n children stemming from m parents, mutate them, rate them |
492
|
|
|
|
|
|
|
sub manage_children { |
493
|
1380
|
|
|
1380
|
|
2427
|
my $obj = shift; |
494
|
|
|
|
|
|
|
|
495
|
1380
|
|
|
|
|
10329
|
my $debug = $obj->{'debug'}; |
496
|
1380
|
|
|
|
|
2804
|
my $dfh = $obj->{'debug_handle'}; |
497
|
|
|
|
|
|
|
|
498
|
1380
|
|
|
|
|
2826
|
my $nchld = $obj->{'children'}; |
499
|
1380
|
|
|
|
|
2425
|
my $nindy = $obj->{'individuals'}; |
500
|
1380
|
|
|
|
|
2575
|
my $npar = $obj->{'parents'}; |
501
|
|
|
|
|
|
|
|
502
|
1380
|
|
|
|
|
2318
|
my @new_children = (); |
503
|
|
|
|
|
|
|
|
504
|
1380
|
|
|
|
|
2915
|
$obj->{'children_list'} = []; |
505
|
|
|
|
|
|
|
|
506
|
1380
|
50
|
|
|
|
119055
|
if ($debug) { |
507
|
0
|
|
|
|
|
0
|
print $dfh " Managing children\n"; |
508
|
|
|
|
|
|
|
|
509
|
0
|
|
|
|
|
0
|
print $dfh " Parents\n"; |
510
|
0
|
|
|
|
|
0
|
my $pp=0; |
511
|
0
|
|
|
|
|
0
|
foreach my $p (@{$obj->{'individuals_list'}}) { |
|
0
|
|
|
|
|
0
|
|
512
|
0
|
|
|
|
|
0
|
print $dfh "Parent $pp = ",$p->pretty_genes(),"\n"; |
513
|
0
|
|
|
|
|
0
|
$pp++; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
# Create children |
518
|
1380
|
|
|
|
|
3446
|
for my $nc (1..$nchld) { |
519
|
25700
|
|
|
|
|
73518
|
my $child = Math::ES::Individuum->new(); |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
# Determine parents |
522
|
25700
|
|
|
|
|
46548
|
my @parents_idx = (); |
523
|
25700
|
|
|
|
|
48147
|
my @parents_list = (); |
524
|
25700
|
|
|
|
|
48828
|
for my $np (1..$npar) { |
525
|
56144
|
|
|
|
|
171523
|
my $num = random_uniform_integer(1, 0,$nindy-1); |
526
|
56144
|
100
|
|
|
|
923675
|
if (grep(/^$num$/, @parents_idx)) { |
527
|
4744
|
|
|
|
|
7232
|
redo; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
else { |
530
|
51400
|
|
|
|
|
83566
|
push (@parents_idx, $num) ; |
531
|
51400
|
|
|
|
|
141575
|
push (@parents_list, $obj->{'individuals_list'}[$num]); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# Now do the origination (data copy and crossover) |
536
|
25700
|
50
|
|
|
|
58586
|
print $dfh " Parents chosen for crossover ",join(' : ',@parents_idx),"\n" if($debug); |
537
|
25700
|
|
|
|
|
64190
|
$child->originate(@parents_list); |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
# ... mutate it ... |
540
|
25700
|
|
|
|
|
73263
|
$child->mutate(); |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# ... and rate it |
543
|
25700
|
|
|
|
|
73861
|
$child->rate(); |
544
|
|
|
|
|
|
|
|
545
|
25700
|
|
|
|
|
27055
|
push (@{$obj->{'children_list'}}, $child); |
|
25700
|
|
|
|
|
61091
|
|
546
|
|
|
|
|
|
|
|
547
|
25700
|
50
|
|
|
|
93702
|
print $dfh "Child $nc = ",$child->pretty_genes()," >=> ",$child->rate(),"\n" if ($debug); |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
1380
|
|
|
|
|
6808
|
$obj->rank_children(); |
551
|
|
|
|
|
|
|
|
552
|
1380
|
|
|
|
|
3040
|
return(@{$obj->{'children_list'}}); |
|
1380
|
|
|
|
|
5552
|
|
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# ------------- |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub rate_individuals { |
558
|
2892
|
|
|
2892
|
|
4009
|
my $obj = shift; |
559
|
|
|
|
|
|
|
|
560
|
2892
|
100
|
66
|
|
|
14626
|
unless (exists($obj->{'pop_rate_individuals'}) or defined($obj->{'pop_rate_individuals'}) ) { |
561
|
8
|
|
|
|
|
13
|
$obj->{'pop_rate_individuals'} = 0; |
562
|
8
|
|
|
|
|
9
|
foreach my $indy (@{$obj->{'individuals_list'}}) { |
|
8
|
|
|
|
|
18
|
|
563
|
60
|
|
|
|
|
134
|
$obj->{'pop_rate_individuals'} += $indy->rate(); |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
2892
|
|
|
|
|
4922
|
return($obj->{'pop_rate_individuals'}); |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
# ------------- |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub rank_individuals { |
573
|
2852
|
|
|
2852
|
|
7019
|
my $obj = shift; |
574
|
|
|
|
|
|
|
|
575
|
2852
|
|
|
|
|
8008
|
$obj->rate_individuals(); |
576
|
|
|
|
|
|
|
|
577
|
2852
|
|
|
|
|
3804
|
my @temp = sort { $a->rate() <=> $b->rate() } (@{$obj->{'individuals_list'}}); |
|
41895
|
|
|
|
|
85112
|
|
|
2852
|
|
|
|
|
8585
|
|
578
|
2852
|
|
|
|
|
9362
|
$obj->{'individuals_list'} = [@temp]; |
579
|
|
|
|
|
|
|
|
580
|
2852
|
|
|
|
|
5939
|
my @temp2; |
581
|
2852
|
|
|
|
|
4223
|
foreach my $indy (@{$obj->{'individuals_list'}}) { |
|
2852
|
|
|
|
|
6286
|
|
582
|
22250
|
|
|
|
|
41613
|
push (@temp2, $indy->rate()); |
583
|
|
|
|
|
|
|
} |
584
|
2852
|
|
|
|
|
10272
|
$obj->{'ranked_rates_individuals'} = [@temp2]; |
585
|
2852
|
|
|
|
|
11851
|
return(\@temp2); |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# ------------- |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub rate_children { |
591
|
1380
|
|
|
1380
|
|
2024
|
my $obj = shift; |
592
|
|
|
|
|
|
|
|
593
|
1380
|
100
|
66
|
|
|
7321
|
unless (exists($obj->{'pop_rate_children'}) or defined($obj->{'pop_rate_children'}) ) { |
594
|
8
|
|
|
|
|
363
|
$obj->{'pop_rate_children'} = 0; |
595
|
8
|
|
|
|
|
11
|
foreach my $indy (@{$obj->{'children_list'}}) { |
|
8
|
|
|
|
|
22
|
|
596
|
160
|
|
|
|
|
1825
|
$obj->{'pop_rate_children'} += $indy->rate(); |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
1380
|
|
|
|
|
3830
|
return($obj->{'pop_rate_children'}); |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# ------------- |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub rank_children { |
606
|
1380
|
|
|
1380
|
|
2089
|
my $obj = shift; |
607
|
|
|
|
|
|
|
|
608
|
1380
|
|
|
|
|
4254
|
$obj->rate_children(); |
609
|
|
|
|
|
|
|
|
610
|
1380
|
|
|
|
|
1848
|
my @temp = sort { $a->rate() <=> $b->rate() } (@{$obj->{'children_list'}}); |
|
75101
|
|
|
|
|
141570
|
|
|
1380
|
|
|
|
|
10507
|
|
611
|
1380
|
|
|
|
|
8133
|
$obj->{'children_list'} = [@temp]; |
612
|
|
|
|
|
|
|
|
613
|
1380
|
|
|
|
|
3884
|
my @temp2; |
614
|
1380
|
|
|
|
|
2164
|
foreach my $indy (@{$obj->{'children_list'}}) { |
|
1380
|
|
|
|
|
3298
|
|
615
|
25700
|
|
|
|
|
47557
|
push (@temp2, $indy->rate()); |
616
|
|
|
|
|
|
|
} |
617
|
1380
|
|
|
|
|
11174
|
$obj->{'ranked_rates_children'} = [@temp2]; |
618
|
1380
|
|
|
|
|
8475
|
return(\@temp2); |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# ------------- |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
sub do_selection { |
624
|
1380
|
|
|
1380
|
|
2175
|
my $obj = shift; |
625
|
|
|
|
|
|
|
|
626
|
1380
|
|
|
|
|
2457
|
my @new_indies = (); |
627
|
|
|
|
|
|
|
|
628
|
1380
|
|
|
|
|
3004
|
my $nchld = $obj->{'children'}; |
629
|
1380
|
|
|
|
|
3722
|
my $nindy = $obj->{'individuals'}; |
630
|
1380
|
|
|
|
|
2285
|
my $elite = $obj->{'elite'}; |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# Respect the elite |
633
|
1380
|
100
|
66
|
|
|
9237
|
if ($elite > 0 and $elite <= $nindy ) { |
634
|
1080
|
|
|
|
|
1728
|
my @temp = sort { $a->rate() <=> $b->rate() } (@{$obj->{'children_list'}}, @{$obj->{'individuals_list'}}); |
|
60828
|
|
|
|
|
108784
|
|
|
1080
|
|
|
|
|
2284
|
|
|
1080
|
|
|
|
|
4961
|
|
635
|
|
|
|
|
|
|
|
636
|
1080
|
|
|
|
|
3286
|
for my $i (1..$elite) { |
637
|
1280
|
|
|
|
|
5760
|
push (@new_indies, $temp[$i-1]); |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
# Deal with the rest |
642
|
1380
|
|
|
|
|
3933
|
my $nrest = $nindy - $elite; |
643
|
1380
|
50
|
|
|
|
3738
|
if ($nrest > 0) { |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
# Selection according to scheme |
646
|
1380
|
|
|
|
|
2792
|
my $scheme = $obj->{'selection_scheme'}; |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# 1 = Select n best |
649
|
1380
|
100
|
|
|
|
3549
|
if ($scheme == 1) { |
|
|
50
|
|
|
|
|
|
650
|
1180
|
|
|
|
|
2486
|
foreach my $i (1..$nrest) { |
651
|
6520
|
|
|
|
|
11464
|
push (@new_indies, $obj->{'children_list'}[$i-1]); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
# 2 = Select n-1 best and one random other |
656
|
|
|
|
|
|
|
elsif ($scheme == 2) { |
657
|
200
|
|
|
|
|
497
|
foreach my $i (1..$nrest-1) { |
658
|
1400
|
|
|
|
|
2378
|
push (@new_indies, $obj->{'children_list'}[$i-1]); |
659
|
|
|
|
|
|
|
} |
660
|
200
|
|
|
|
|
818
|
my $lastone = random_uniform_integer(0, $nrest, $nchld); |
661
|
200
|
|
|
|
|
2463
|
push (@new_indies, $obj->{'children_list'}[$lastone-1]); |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
# Move to next generation |
667
|
1380
|
|
|
|
|
4462
|
$obj->{'individuals_list'} = [@new_indies]; |
668
|
1380
|
|
|
|
|
55593
|
$obj->{'pop_counter'}++; |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# ------------- |
673
|
|
|
|
|
|
|
# Withdraw a number of individuals from the population |
674
|
|
|
|
|
|
|
# but spare the elite. |
675
|
|
|
|
|
|
|
# |
676
|
|
|
|
|
|
|
sub withdraw_random_individual { |
677
|
600
|
|
|
600
|
|
664
|
my $obj = shift; |
678
|
|
|
|
|
|
|
|
679
|
600
|
|
50
|
|
|
4587
|
my $num = (shift || 1); |
680
|
|
|
|
|
|
|
|
681
|
600
|
|
|
|
|
747
|
my ($nindy, $elite); |
682
|
600
|
|
|
|
|
985
|
$elite = $obj->{'elite'}; |
683
|
|
|
|
|
|
|
|
684
|
600
|
|
|
|
|
1064
|
my @withdrawn = (); |
685
|
600
|
|
|
|
|
1107
|
for my $i (1..$num) { |
686
|
|
|
|
|
|
|
|
687
|
600
|
|
|
|
|
1050
|
$nindy = $obj->{'individuals'}; |
688
|
600
|
50
|
|
|
|
1425
|
last if ($nindy-$elite <= 0); |
689
|
600
|
50
|
|
|
|
1150
|
last if ($nindy == 0); |
690
|
|
|
|
|
|
|
|
691
|
600
|
|
|
|
|
2386
|
my $num = random_uniform_integer(0, $elite+1, $nindy); |
692
|
|
|
|
|
|
|
|
693
|
600
|
|
|
|
|
6912
|
$obj->{'individuals'}--; |
694
|
600
|
|
|
|
|
758
|
push (@withdrawn, splice(@{$obj->{'individuals_list'}},$num-1,1)); |
|
600
|
|
|
|
|
13373
|
|
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
600
|
|
|
|
|
1514
|
$obj->rank_individuals(); |
698
|
|
|
|
|
|
|
|
699
|
600
|
|
|
|
|
2106
|
return(@withdrawn); |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
# ------------- |
703
|
|
|
|
|
|
|
# Withdraw all individuals |
704
|
|
|
|
|
|
|
# |
705
|
|
|
|
|
|
|
sub withdraw_all_individual { |
706
|
10
|
|
|
10
|
|
16
|
my $obj = shift; |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
|
709
|
10
|
|
|
|
|
11
|
my @withdrawn = @{$obj->{'individuals_list'}}; |
|
10
|
|
|
|
|
34
|
|
710
|
10
|
|
|
|
|
19
|
$obj->{'individuals_list'} = []; |
711
|
10
|
|
|
|
|
24
|
$obj->{'individuals'} = 0; |
712
|
|
|
|
|
|
|
|
713
|
10
|
|
|
|
|
35
|
return(@withdrawn); |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
# ------------- |
717
|
|
|
|
|
|
|
# Add a number of new individuals to the population |
718
|
|
|
|
|
|
|
# |
719
|
|
|
|
|
|
|
sub integrate_individual { |
720
|
680
|
|
|
680
|
|
800
|
my $obj = shift; |
721
|
|
|
|
|
|
|
|
722
|
680
|
|
|
|
|
1114
|
foreach my $indy (@_) { |
723
|
680
|
|
|
|
|
1069
|
$obj->{'individuals'}++; |
724
|
680
|
|
|
|
|
779
|
push (@{$obj->{'individuals_list'}}, $indy); |
|
680
|
|
|
|
|
2160
|
|
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
680
|
|
|
|
|
1409
|
$obj->rank_individuals(); |
728
|
|
|
|
|
|
|
|
729
|
680
|
|
|
|
|
2180
|
return($obj); |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
734
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
735
|
|
|
|
|
|
|
package Math::ES::Individuum; |
736
|
1
|
|
|
1
|
|
7
|
use Math::Random qw(random_normal random_uniform); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
934
|
|
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# ----------- |
739
|
|
|
|
|
|
|
# Constructor of a new individuum |
740
|
|
|
|
|
|
|
# |
741
|
|
|
|
|
|
|
sub new { |
742
|
25760
|
|
|
25760
|
|
41772
|
my $name = shift; |
743
|
25760
|
|
|
|
|
76378
|
my $obj = bless {@_}, $name; |
744
|
|
|
|
|
|
|
|
745
|
25760
|
|
|
|
|
58287
|
$obj->{'indy_rate'} = undef; |
746
|
|
|
|
|
|
|
|
747
|
25760
|
100
|
|
|
|
57400
|
if ($obj->{'mutate'}) { |
748
|
52
|
|
|
|
|
105
|
$obj->mutate; |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
|
751
|
25760
|
|
|
|
|
45706
|
return ($obj); |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# ----------- |
755
|
|
|
|
|
|
|
# Return the rating function value of the individuum |
756
|
|
|
|
|
|
|
# |
757
|
|
|
|
|
|
|
# |
758
|
|
|
|
|
|
|
sub rate { |
759
|
429887
|
|
|
429887
|
|
526214
|
my $obj = shift; |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
# Call the rating function (if no value is present) |
763
|
|
|
|
|
|
|
# |
764
|
|
|
|
|
|
|
# &function(@values) returns a result |
765
|
429887
|
100
|
|
|
|
834813
|
unless (defined $obj->{'indy_rate'}) { |
766
|
25760
|
|
|
|
|
25492
|
$obj->{'indy_rate'} = &{$obj->{'rating_function'}}( @{$obj->{'genes'}} ); |
|
25760
|
|
|
|
|
84474
|
|
|
25760
|
|
|
|
|
46956
|
|
767
|
|
|
|
|
|
|
} |
768
|
429887
|
|
|
|
|
1237003
|
return ($obj->{'indy_rate'}); |
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# ----------- |
773
|
|
|
|
|
|
|
# Do mutation on individuum |
774
|
|
|
|
|
|
|
# |
775
|
|
|
|
|
|
|
# $obj->mutate(); |
776
|
|
|
|
|
|
|
# |
777
|
|
|
|
|
|
|
sub mutate { |
778
|
|
|
|
|
|
|
|
779
|
25752
|
|
|
25752
|
|
37781
|
my $obj = shift; |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
# Firstly mutate deviations |
782
|
25752
|
|
|
|
|
37864
|
my $i=-1; |
783
|
25752
|
|
|
|
|
25612
|
foreach my $gd (@{$obj->{'gene_deviations'}}) { |
|
25752
|
|
|
|
|
60370
|
|
784
|
142656
|
|
|
|
|
383633
|
my $rnn = random_normal(0,0, $obj->{'variance_mutator'}); |
785
|
142656
|
|
|
|
|
1175847
|
$i++; |
786
|
142656
|
|
|
|
|
225606
|
my $tmp = $gd * exp($rnn); |
787
|
142656
|
50
|
33
|
|
|
652204
|
if (defined($obj->{'max_gene_deviations'}[$i]) and |
|
|
50
|
33
|
|
|
|
|
788
|
|
|
|
|
|
|
$tmp > $obj->{'max_gene_deviations'}[$i]) { |
789
|
0
|
|
|
|
|
0
|
$gd = $obj->{'max_gene_deviations'}[$i]; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
elsif (defined($obj->{'min_gene_deviations'}[$i]) and |
792
|
|
|
|
|
|
|
$tmp < $obj->{'min_gene_deviations'}[$i]) { |
793
|
0
|
|
|
|
|
0
|
$gd = $obj->{'min_gene_deviations'}[$i]; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
else { |
796
|
142656
|
|
|
|
|
254245
|
$gd = $tmp; |
797
|
|
|
|
|
|
|
}; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
# Secondly mutate genes |
801
|
25752
|
|
|
|
|
36938
|
my $n = @{$obj->{'genes'}}; |
|
25752
|
|
|
|
|
45925
|
|
802
|
25752
|
|
|
|
|
62098
|
for (my $i=0; $i<$n; $i++) { |
803
|
|
|
|
|
|
|
|
804
|
719138
|
|
|
|
|
997489
|
Try: { |
805
|
142656
|
|
|
|
|
151693
|
my $var = $obj->{'stepwidth_var'}; |
806
|
719138
|
100
|
|
|
|
1658469
|
my $factor = ( random_uniform() > 0.5 ? $var : 1/$var ) * $obj->{'stepwidth_const'}; |
807
|
|
|
|
|
|
|
|
808
|
719138
|
|
|
|
|
4209032
|
my $gd = $obj->{'gene_deviations'}[$i]; |
809
|
719138
|
|
|
|
|
1826651
|
my $rnn = random_normal(0,0,$gd); |
810
|
|
|
|
|
|
|
|
811
|
719138
|
|
|
|
|
6344406
|
my $temp = $obj->{'genes'}[$i] + ($rnn * $factor); |
812
|
719138
|
100
|
|
|
|
1818894
|
redo Try if ($temp > $obj->{'max_gene_values'}[$i]); |
813
|
439389
|
100
|
|
|
|
1036059
|
redo Try if ($temp < $obj->{'min_gene_values'}[$i]); |
814
|
|
|
|
|
|
|
|
815
|
142656
|
|
|
|
|
451512
|
$obj->{'genes'}[$i] = $temp; |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
25752
|
|
|
|
|
41872
|
return (1); |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# ----------- |
824
|
|
|
|
|
|
|
# Simulate the originating process of a new individuum. |
825
|
|
|
|
|
|
|
# |
826
|
|
|
|
|
|
|
# $child_obj->originate($parent1, $parent1, ...) |
827
|
|
|
|
|
|
|
# |
828
|
|
|
|
|
|
|
sub originate { |
829
|
25700
|
|
|
25700
|
|
34081
|
my $obj = shift; |
830
|
25700
|
|
|
|
|
44851
|
my @parents = @_; # Allow more than 1 or 2 cross over parents |
831
|
|
|
|
|
|
|
|
832
|
25700
|
|
|
|
|
30071
|
my $np = @parents; |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# Copy all info from first parent |
835
|
25700
|
|
|
|
|
57664
|
$parents[0]->copy_to($obj); |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# ... but reset the value !!! |
838
|
25700
|
|
|
|
|
36501
|
$obj->{'indy_rate'} = undef; |
839
|
|
|
|
|
|
|
|
840
|
25700
|
|
|
|
|
27415
|
my $n = @{$obj->{'genes'}}; |
|
25700
|
|
|
|
|
41196
|
|
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
# We have more than one parent, do the crossover |
843
|
25700
|
50
|
|
|
|
53786
|
unless ($np == 1) { |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
# Iterate over the genes |
846
|
25700
|
|
|
|
|
60541
|
for (my $i=0; $i<$n; $i++) { |
847
|
142400
|
|
|
|
|
342324
|
my $rnu = random_uniform(); |
848
|
|
|
|
|
|
|
# print "Random Number: $rnu\n"; |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
# Find the appropriate parent |
851
|
142400
|
|
|
|
|
839214
|
Parent: for (my $p=0; $p<$np; $p++) { |
852
|
213318
|
100
|
|
|
|
549578
|
if ($rnu <= 1/$np*($p+1)) { |
853
|
142400
|
|
|
|
|
295192
|
$obj->{'genes'}[$i] = $parents[$p]->{'genes'}[$i]; |
854
|
142400
|
|
|
|
|
259465
|
$obj->{'gene_deviations'}[$i] = $parents[$p]->{'gene_deviations'}[$i]; |
855
|
142400
|
|
|
|
|
377880
|
last Parent; |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
} |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
} |
861
|
25700
|
|
|
|
|
44815
|
return ($obj); |
862
|
|
|
|
|
|
|
} |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
# ----------- |
865
|
|
|
|
|
|
|
# Copy operator for an individuum |
866
|
|
|
|
|
|
|
# $from_obj->copy_to($to_obj); |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
sub copy_to { |
869
|
25700
|
|
|
25700
|
|
30011
|
my $obj = shift; |
870
|
25700
|
|
|
|
|
25466
|
my $new = shift; |
871
|
|
|
|
|
|
|
|
872
|
25700
|
|
|
|
|
27535
|
foreach (keys (%{$obj})) { |
|
25700
|
|
|
|
|
134346
|
|
873
|
359752
|
|
|
|
|
515399
|
my $temp = $obj->{$_}; |
874
|
359752
|
100
|
|
|
|
834351
|
if (ref($temp) =~ 'ARRAY') { |
|
|
50
|
|
|
|
|
|
875
|
154152
|
|
|
|
|
615508
|
$new->{$_} = [@$temp]; |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
elsif (ref($temp) =~ 'HASH') { |
878
|
0
|
|
|
|
|
0
|
$new->{$_} = {%$temp}; |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
else { |
881
|
205600
|
|
|
|
|
407443
|
$new->{$_} = $temp; # Scalars and programs go here |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
}; |
884
|
25700
|
|
|
|
|
79325
|
return ($new); |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# ----------- |
888
|
|
|
|
|
|
|
# Return the genes and variances in a 'pretty' style |
889
|
|
|
|
|
|
|
# |
890
|
|
|
|
|
|
|
sub pretty_genes { |
891
|
1380
|
|
|
1380
|
|
2611
|
my $obj = shift; |
892
|
|
|
|
|
|
|
|
893
|
1380
|
|
|
|
|
1717
|
my $n = @{$obj->{'genes'}}; |
|
1380
|
|
|
|
|
3376
|
|
894
|
1380
|
|
|
|
|
7605
|
my $output; |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
# Iterate over the genes |
897
|
1380
|
|
|
|
|
4633
|
for (my $i=0; $i<$n; $i++) { |
898
|
8160
|
|
|
|
|
70250
|
$output .= sprintf("%10.6f", $obj->{'genes'}[$i]) |
899
|
|
|
|
|
|
|
. ' (' . sprintf("%10.6f", $obj->{'gene_deviations'}[$i]) . ')'; |
900
|
|
|
|
|
|
|
} |
901
|
1380
|
|
|
|
|
6578
|
return ($output); |
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
1; |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
__END__ |