line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package AI::Genetic::Pro; |
2
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
664170
|
use vars qw($VERSION); |
|
15
|
|
|
|
|
43
|
|
|
15
|
|
|
|
|
1315
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
$VERSION = 0.401; |
6
|
|
|
|
|
|
|
#--------------- |
7
|
|
|
|
|
|
|
|
8
|
15
|
|
|
15
|
|
85
|
use warnings; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
794
|
|
9
|
15
|
|
|
15
|
|
97
|
use strict; |
|
15
|
|
|
|
|
238
|
|
|
15
|
|
|
|
|
718
|
|
10
|
15
|
|
|
15
|
|
893
|
use lib qw(../lib/perl); |
|
15
|
|
|
|
|
685
|
|
|
15
|
|
|
|
|
106
|
|
11
|
15
|
|
|
15
|
|
1703
|
use Carp; |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
27692
|
|
12
|
15
|
|
|
15
|
|
13251
|
use Clone qw(clone); |
|
15
|
|
|
|
|
76444
|
|
|
15
|
|
|
|
|
4288
|
|
13
|
15
|
|
|
15
|
|
16440
|
use Struct::Compare; |
|
15
|
|
|
|
|
17041
|
|
|
15
|
|
|
|
|
913
|
|
14
|
15
|
|
|
15
|
|
119
|
use Digest::MD5 qw(md5_hex); |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
1106
|
|
15
|
15
|
|
|
15
|
|
88
|
use List::Util qw(sum); |
|
15
|
|
|
|
|
27
|
|
|
15
|
|
|
|
|
12800
|
|
16
|
15
|
|
|
15
|
|
228764
|
use List::MoreUtils qw(minmax first_index apply); |
|
15
|
|
|
|
|
32562
|
|
|
15
|
|
|
|
|
1654
|
|
17
|
|
|
|
|
|
|
#use Data::Dumper; $Data::Dumper::Sortkeys = 1; |
18
|
15
|
|
|
15
|
|
14258
|
use UNIVERSAL::require; |
|
15
|
|
|
|
|
30365
|
|
|
15
|
|
|
|
|
162
|
|
19
|
15
|
|
|
15
|
|
39100
|
use AI::Genetic::Pro::Array::Type qw(get_package_by_element_size); |
|
15
|
|
|
|
|
72
|
|
|
15
|
|
|
|
|
141
|
|
20
|
15
|
|
|
15
|
|
26318
|
use AI::Genetic::Pro::Chromosome; |
|
15
|
|
|
|
|
52
|
|
|
15
|
|
|
|
|
208
|
|
21
|
15
|
|
|
15
|
|
474
|
use base qw(Class::Accessor::Fast::XS); |
|
15
|
|
|
|
|
51
|
|
|
15
|
|
|
|
|
37586
|
|
22
|
|
|
|
|
|
|
#----------------------------------------------------------------------- |
23
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors(qw( |
24
|
|
|
|
|
|
|
type |
25
|
|
|
|
|
|
|
population |
26
|
|
|
|
|
|
|
terminate |
27
|
|
|
|
|
|
|
chromosomes |
28
|
|
|
|
|
|
|
crossover |
29
|
|
|
|
|
|
|
parents _parents |
30
|
|
|
|
|
|
|
history _history |
31
|
|
|
|
|
|
|
fitness _fitness _fitness_real |
32
|
|
|
|
|
|
|
cache |
33
|
|
|
|
|
|
|
mutation _mutator |
34
|
|
|
|
|
|
|
strategy _strategist |
35
|
|
|
|
|
|
|
selection _selector |
36
|
|
|
|
|
|
|
_translations |
37
|
|
|
|
|
|
|
generation |
38
|
|
|
|
|
|
|
preserve |
39
|
|
|
|
|
|
|
variable_length |
40
|
|
|
|
|
|
|
_fix_range |
41
|
|
|
|
|
|
|
_package |
42
|
|
|
|
|
|
|
strict _strict |
43
|
|
|
|
|
|
|
)); |
44
|
|
|
|
|
|
|
#======================================================================= |
45
|
|
|
|
|
|
|
# Additional modules |
46
|
15
|
|
|
15
|
|
245124
|
use constant STORABLE => 'Storable'; |
|
15
|
|
|
|
|
42
|
|
|
15
|
|
|
|
|
1493
|
|
47
|
15
|
|
|
15
|
|
91
|
use constant GD => 'GD::Graph::linespoints'; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
113356
|
|
48
|
|
|
|
|
|
|
#======================================================================= |
49
|
|
|
|
|
|
|
my $_Cache = { }; |
50
|
|
|
|
|
|
|
my $_temp_chromosome; |
51
|
|
|
|
|
|
|
#======================================================================= |
52
|
|
|
|
|
|
|
sub new { |
53
|
15
|
|
|
15
|
1
|
1356
|
my $class = shift; |
54
|
|
|
|
|
|
|
|
55
|
15
|
100
|
|
|
|
58
|
my %opts = map { if(ref $_){$_}else{ /^-?(.*)$/o; $1 }} @_; |
|
390
|
|
|
|
|
651
|
|
|
60
|
|
|
|
|
107
|
|
|
330
|
|
|
|
|
1013
|
|
|
330
|
|
|
|
|
1190
|
|
56
|
15
|
|
|
|
|
94
|
my $self = bless \%opts, $class; |
57
|
|
|
|
|
|
|
|
58
|
15
|
50
|
66
|
|
|
179
|
croak(q/Type of chromosomes cannot be "combination" if "variable length" feature is active!/) |
59
|
|
|
|
|
|
|
if $self->type eq q/combination/ and $self->variable_length; |
60
|
15
|
50
|
|
|
|
148
|
croak(q/You must specify a crossover strategy with -strategy!/) |
61
|
|
|
|
|
|
|
unless defined ($self->strategy); |
62
|
15
|
50
|
33
|
|
|
108
|
croak(q/Type of chromosomes cannot be "combination" if strategy is not one of: OX, PMX!/) |
|
|
|
66
|
|
|
|
|
63
|
|
|
|
|
|
|
if $self->type eq q/combination/ and ($self->strategy->[0] ne q/OX/ and $self->strategy->[0] ne q/PMX/); |
64
|
15
|
50
|
66
|
|
|
469
|
croak(q/Strategy cannot be "/,$self->strategy->[0],q/" if "variable length" feature is active!/ ) |
|
|
|
66
|
|
|
|
|
65
|
|
|
|
|
|
|
if ($self->strategy->[0] eq 'PMX' or $self->strategy->[0] eq 'OX') and $self->variable_length; |
66
|
|
|
|
|
|
|
|
67
|
15
|
50
|
|
|
|
123
|
$self->_set_strict if $self->strict; |
68
|
|
|
|
|
|
|
|
69
|
15
|
|
|
|
|
84
|
return $self; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
#======================================================================= |
72
|
0
|
|
|
0
|
|
0
|
sub _Cache { $_Cache; } |
73
|
|
|
|
|
|
|
#======================================================================= |
74
|
|
|
|
|
|
|
# INIT ################################################################# |
75
|
|
|
|
|
|
|
#======================================================================= |
76
|
|
|
|
|
|
|
sub _set_strict { |
77
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# fitness |
80
|
0
|
|
|
|
|
0
|
my $fitness = $self->fitness(); |
81
|
|
|
|
|
|
|
my $replacement = sub { |
82
|
0
|
|
|
0
|
|
0
|
my @tmp = @{$_[1]}; |
|
0
|
|
|
|
|
0
|
|
83
|
0
|
|
|
|
|
0
|
my $ret = $fitness->(@_); |
84
|
0
|
|
|
|
|
0
|
my @cmp = @{$_[1]}; |
|
0
|
|
|
|
|
0
|
|
85
|
0
|
0
|
|
|
|
0
|
die qq/Chromosome was modified in a fitness function from "@tmp" to "@{$_[1]}"!\n/ unless compare(\@tmp, \@cmp); |
|
0
|
|
|
|
|
0
|
|
86
|
0
|
|
|
|
|
0
|
return $ret; |
87
|
0
|
|
|
|
|
0
|
}; |
88
|
0
|
|
|
|
|
0
|
$self->fitness($replacement); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
#======================================================================= |
91
|
|
|
|
|
|
|
sub _fitness_cached { |
92
|
46235
|
|
|
46235
|
|
69391
|
my ($self, $chromosome) = @_; |
93
|
46235
|
|
|
|
|
63894
|
my $key = md5_hex(${tied(@$chromosome)}); |
|
46235
|
|
|
|
|
236973
|
|
94
|
46235
|
100
|
|
|
|
361019
|
return $_Cache->{$key} if exists $_Cache->{$key}; |
95
|
4001
|
|
|
|
|
26945
|
$_Cache->{$key} = $self->_fitness_real->($self, $chromosome); |
96
|
4001
|
|
|
|
|
278119
|
return $_Cache->{$key}; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
#======================================================================= |
99
|
|
|
|
|
|
|
sub _init_cache { |
100
|
13
|
|
|
13
|
|
38
|
my ($self) = @_; |
101
|
|
|
|
|
|
|
|
102
|
13
|
|
|
|
|
103
|
$self->_fitness_real($self->fitness); |
103
|
13
|
|
|
|
|
63
|
$self->fitness(\&_fitness_cached); |
104
|
13
|
|
|
|
|
30
|
return; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
#======================================================================= |
107
|
|
|
|
|
|
|
sub _check_data_ref { |
108
|
6
|
|
|
6
|
|
14
|
my ($self, $data_org) = @_; |
109
|
6
|
|
|
|
|
490
|
my $data = clone($data_org); |
110
|
6
|
|
|
|
|
12
|
my $ars; |
111
|
6
|
|
|
|
|
24
|
for(0..$#$data){ |
112
|
48
|
50
|
|
|
|
130
|
next if $ars->{$data->[$_]}; |
113
|
48
|
|
|
|
|
110
|
$ars->{$data->[$_]} = 1; |
114
|
48
|
|
|
|
|
47
|
unshift @{$data->[$_]}, undef; |
|
48
|
|
|
|
|
186
|
|
115
|
|
|
|
|
|
|
} |
116
|
6
|
|
|
|
|
45
|
return $data; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
#======================================================================= |
119
|
|
|
|
|
|
|
# we have to find C to (in some cases) incrase value of range |
120
|
|
|
|
|
|
|
# due to design model |
121
|
|
|
|
|
|
|
sub _find_fix_range { |
122
|
3
|
|
|
3
|
|
8
|
my ($self, $data) = @_; |
123
|
|
|
|
|
|
|
|
124
|
3
|
|
|
|
|
8
|
for my $idx (0..$#$data){ |
125
|
24
|
50
|
|
|
|
44
|
if($data->[$idx]->[1] < 1){ |
126
|
24
|
|
|
|
|
33
|
my $const = 1 - $data->[$idx]->[1]; |
127
|
24
|
|
|
|
|
24
|
push @{$self->_fix_range}, $const; |
|
24
|
|
|
|
|
58
|
|
128
|
24
|
|
|
|
|
31
|
$data->[$idx]->[1] += $const; |
129
|
24
|
|
|
|
|
40
|
$data->[$idx]->[2] += $const; |
130
|
0
|
|
|
|
|
0
|
}else{ push @{$self->_fix_range}, 0; } |
|
0
|
|
|
|
|
0
|
|
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
3
|
|
|
|
|
25
|
return $data; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
#======================================================================= |
136
|
|
|
|
|
|
|
sub init { |
137
|
15
|
|
|
15
|
1
|
285
|
my ($self, $data) = @_; |
138
|
|
|
|
|
|
|
|
139
|
15
|
50
|
|
|
|
70
|
croak q/You have to pass some data to "init"!/ unless $data; |
140
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
141
|
15
|
|
|
|
|
86
|
$self->generation(0); |
142
|
15
|
|
|
|
|
75
|
$self->_fitness( { } ); |
143
|
15
|
|
|
|
|
84
|
$self->_fix_range( [ ] ); |
144
|
15
|
|
|
|
|
163
|
$self->_history( [ [ ], [ ], [ ] ] ); |
145
|
15
|
100
|
|
|
|
149
|
$self->_init_cache if $self->cache; |
146
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
147
|
|
|
|
|
|
|
|
148
|
15
|
100
|
|
|
|
178
|
if($self->type eq q/listvector/){ |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
149
|
3
|
50
|
|
|
|
22
|
croak(q/You have to pass array reference if "type" is set to "listvector"/) unless ref $data eq 'ARRAY'; |
150
|
3
|
|
|
|
|
14
|
$self->_translations( $self->_check_data_ref($data) ); |
151
|
|
|
|
|
|
|
}elsif($self->type eq q/bitvector/){ |
152
|
8
|
50
|
|
|
|
64
|
croak(q/You have to pass integer if "type" is set to "bitvector"/) if $data !~ /^\d+$/o; |
153
|
8
|
|
|
|
|
41
|
$self->_translations( [ [ 0, 1 ] ] ); |
154
|
8
|
|
|
|
|
443
|
$self->_translations->[$_] = $self->_translations->[0] for 1..$data-1; |
155
|
|
|
|
|
|
|
}elsif($self->type eq q/combination/){ |
156
|
1
|
50
|
|
|
|
5
|
croak(q/You have to pass array reference if "type" is set to "combination"/) unless ref $data eq 'ARRAY'; |
157
|
1
|
|
|
|
|
31
|
$self->_translations( [ clone($data) ] ); |
158
|
1
|
|
|
|
|
28
|
$self->_translations->[$_] = $self->_translations->[0] for 1..$#$data; |
159
|
|
|
|
|
|
|
}elsif($self->type eq q/rangevector/){ |
160
|
3
|
50
|
|
|
|
14
|
croak(q/You have to pass array reference if "type" is set to "rangevector"/) unless ref $data eq 'ARRAY'; |
161
|
3
|
|
|
|
|
14
|
$self->_translations( $self->_find_fix_range( $self->_check_data_ref($data) )); |
162
|
|
|
|
|
|
|
}else{ |
163
|
0
|
|
|
|
|
0
|
croak(q/You have to specify first "type" of vector!/); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
15
|
|
|
|
|
41
|
my $size = 0; |
167
|
|
|
|
|
|
|
|
168
|
15
|
100
|
|
|
|
97
|
if($self->type ne q/rangevector/){ for(@{$self->_translations}){ $size = $#$_ if $#$_ > $size; } } |
|
12
|
100
|
|
|
|
31
|
|
|
12
|
|
|
|
|
57
|
|
|
288
|
|
|
|
|
583
|
|
169
|
|
|
|
|
|
|
# else{ for(@{$self->_translations}){ $size = $_->[1] if $_->[1] > $size; } } |
170
|
3
|
100
|
|
|
|
7
|
else{ for(@{$self->_translations}){ $size = $_->[2] if $_->[2] > $size; } } # Provisional patch for rangevector values truncated to signed 8-bit quantities. Thx to Tod Hagan |
|
3
|
|
|
|
|
11
|
|
|
24
|
|
|
|
|
56
|
|
171
|
|
|
|
|
|
|
|
172
|
15
|
|
|
|
|
116
|
my $package = get_package_by_element_size($size); |
173
|
15
|
|
|
|
|
84
|
$self->_package($package); |
174
|
|
|
|
|
|
|
|
175
|
15
|
100
|
|
200
|
|
155
|
my $length = ref $data ? sub { $#$data; } : sub { $data - 1 }; |
|
300
|
|
|
|
|
957
|
|
|
420
|
|
|
|
|
2142
|
|
176
|
15
|
100
|
|
|
|
151
|
if($self->variable_length){ |
177
|
6
|
100
|
|
200
|
|
56
|
$length = ref $data ? sub { 1 + int(rand($#$data)); } : sub { 1 + int(rand($data - 1)); }; |
|
400
|
|
|
|
|
1767
|
|
|
200
|
|
|
|
|
799
|
|
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
15
|
|
|
|
|
120
|
$self->chromosomes( [ ] ); |
181
|
1320
|
|
|
|
|
6214
|
push @{$self->chromosomes}, |
182
|
|
|
|
|
|
|
AI::Genetic::Pro::Chromosome->new($self->_translations, $self->type, $package, $length->()) |
183
|
15
|
|
|
|
|
110
|
for 1..$self->population; |
184
|
|
|
|
|
|
|
|
185
|
15
|
|
|
|
|
133
|
$self->_calculate_fitness_all(); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
#======================================================================= |
188
|
|
|
|
|
|
|
# SAVE / LOAD ########################################################## |
189
|
|
|
|
|
|
|
#======================================================================= |
190
|
|
|
|
|
|
|
sub save { |
191
|
0
|
0
|
|
0
|
1
|
0
|
STORABLE->use(qw(store retrieve)) or croak(q/You need "/.STORABLE.q/" module to save a state of "/.__PACKAGE__.q/"!/); |
192
|
0
|
|
|
|
|
0
|
$Storable::Deparse = 1; |
193
|
0
|
|
|
|
|
0
|
$Storable::Eval = 1; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
0
|
my ($self, $file) = @_; |
196
|
0
|
0
|
|
|
|
0
|
croak(q/You have to specify file!/) unless defined $file; |
197
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
0
|
my $clone = { |
199
|
0
|
|
|
|
|
0
|
vector_type => ref(tied(@{$self->chromosomes->[0]})), |
200
|
0
|
|
|
|
|
0
|
chromosomes => [ map { my @genes = @$_; \@genes; } @{$self->chromosomes} ], |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
201
|
|
|
|
|
|
|
_selector => undef, |
202
|
|
|
|
|
|
|
_strategist => undef, |
203
|
|
|
|
|
|
|
_mutator => undef, |
204
|
|
|
|
|
|
|
}; |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
0
|
foreach my $key(keys %$self){ |
207
|
0
|
0
|
|
|
|
0
|
next if exists $clone->{$key}; |
208
|
0
|
|
|
|
|
0
|
$clone->{$key} = $self->{$key}; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
0
|
|
|
|
|
0
|
store($clone, $file); |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
#======================================================================= |
214
|
|
|
|
|
|
|
sub load { |
215
|
0
|
0
|
|
0
|
1
|
0
|
STORABLE->use(qw(store retrieve)) or croak(q/You need "/.STORABLE.q/" module to load a state of "/.__PACKAGE__.q/"!/); |
216
|
0
|
|
|
|
|
0
|
$Storable::Deparse = 1; |
217
|
0
|
|
|
|
|
0
|
$Storable::Eval = 1; |
218
|
|
|
|
|
|
|
|
219
|
0
|
|
|
|
|
0
|
my ($self, $file) = @_; |
220
|
0
|
0
|
|
|
|
0
|
croak(q/You have to specify file!/) unless defined $file; |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
0
|
my $clone = retrieve($file); |
223
|
0
|
0
|
|
|
|
0
|
return carp('Incorrect file!') unless $clone; |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
0
|
$clone->{chromosomes} = [ |
226
|
|
|
|
|
|
|
map { |
227
|
0
|
|
|
|
|
0
|
tie my (@genes), $clone->{vector_type}; |
228
|
0
|
|
|
|
|
0
|
@genes = @$_; |
229
|
0
|
|
|
|
|
0
|
\@genes; |
230
|
0
|
|
|
|
|
0
|
} @{$clone->{chromosomes}} |
231
|
|
|
|
|
|
|
]; |
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
0
|
delete $clone->{vector_type}; |
234
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
0
|
%$self = %$clone; |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
0
|
return 1; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
#======================================================================= |
240
|
|
|
|
|
|
|
# CHARTS ############################################################### |
241
|
|
|
|
|
|
|
#======================================================================= |
242
|
|
|
|
|
|
|
sub chart { |
243
|
0
|
0
|
|
0
|
1
|
0
|
GD->require or croak(q/You need "/.GD.q/" module to draw chart of evolution!/); |
244
|
0
|
|
|
|
|
0
|
my ($self, %params) = (shift, @_); |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
0
|
|
|
0
|
my $graph = GD()->new(($params{-width} || 640), ($params{-height} || 480)); |
|
|
|
0
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
0
|
|
|
|
|
0
|
my $data = $self->getHistory; |
249
|
|
|
|
|
|
|
|
250
|
0
|
0
|
|
|
|
0
|
if(defined $params{-font}){ |
251
|
0
|
|
|
|
|
0
|
$graph->set_title_font ($params{-font}, 12); |
252
|
0
|
|
|
|
|
0
|
$graph->set_x_label_font($params{-font}, 10); |
253
|
0
|
|
|
|
|
0
|
$graph->set_y_label_font($params{-font}, 10); |
254
|
0
|
|
|
|
|
0
|
$graph->set_legend_font ($params{-font}, 8); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
$graph->set_legend( |
258
|
0
|
|
0
|
|
|
0
|
$params{legend1} || q/Max value/, |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
259
|
|
|
|
|
|
|
$params{legend2} || q/Mean value/, |
260
|
|
|
|
|
|
|
$params{legend3} || q/Min value/, |
261
|
|
|
|
|
|
|
); |
262
|
|
|
|
|
|
|
|
263
|
0
|
0
|
0
|
|
|
0
|
$graph->set( |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
264
|
|
|
|
|
|
|
x_label_skip => int(($data->[0]->[-1]*4)/100), |
265
|
|
|
|
|
|
|
x_labels_vertical => 1, |
266
|
|
|
|
|
|
|
x_label_position => .5, |
267
|
|
|
|
|
|
|
y_label_position => .5, |
268
|
|
|
|
|
|
|
y_long_ticks => 1, # poziome linie |
269
|
|
|
|
|
|
|
x_ticks => 1, # poziome linie |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
l_margin => 10, |
272
|
|
|
|
|
|
|
b_margin => 10, |
273
|
|
|
|
|
|
|
r_margin => 10, |
274
|
|
|
|
|
|
|
t_margin => 10, |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
show_values => (defined $params{-show_values} ? 1 : 0), |
277
|
|
|
|
|
|
|
values_vertical => 1, |
278
|
|
|
|
|
|
|
values_format => ($params{-format} || '%.2f'), |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
zero_axis => 1, |
281
|
|
|
|
|
|
|
#interlaced => 1, |
282
|
|
|
|
|
|
|
logo_position => 'BR', |
283
|
|
|
|
|
|
|
legend_placement => 'RT', |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
bgclr => 'white', |
286
|
|
|
|
|
|
|
boxclr => '#FFFFAA', |
287
|
|
|
|
|
|
|
transparent => 0, |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
title => ($params{'-title'} || q/Evolution/ ), |
290
|
|
|
|
|
|
|
x_label => ($params{'-x_label'} || q/Generation/), |
291
|
|
|
|
|
|
|
y_label => ($params{'-y_label'} || q/Value/ ), |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
( $params{-logo} && -f $params{-logo} ? ( logo => $params{-logo} ) : ( ) ) |
294
|
|
|
|
|
|
|
); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
|
297
|
0
|
0
|
|
|
|
0
|
my $gd = $graph->plot( [ [ 0..$#{$data->[0]} ], @$data ] ) or croak($@); |
|
0
|
|
|
|
|
0
|
|
298
|
0
|
0
|
|
|
|
0
|
open(my $fh, '>', $params{-filename}) or croak($@); |
299
|
0
|
|
|
|
|
0
|
binmode $fh; |
300
|
0
|
|
|
|
|
0
|
print $fh $gd->png; |
301
|
0
|
|
|
|
|
0
|
close $fh; |
302
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
0
|
return 1; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
#======================================================================= |
306
|
|
|
|
|
|
|
# TRANSLATIONS ######################################################### |
307
|
|
|
|
|
|
|
#======================================================================= |
308
|
|
|
|
|
|
|
sub as_array_def_only { |
309
|
0
|
|
|
0
|
1
|
0
|
my ($self, $chromosome) = @_; |
310
|
|
|
|
|
|
|
|
311
|
0
|
0
|
0
|
|
|
0
|
return $self->as_array($chromosome) |
312
|
|
|
|
|
|
|
if not $self->variable_length or $self->variable_length < 2; |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
0
|
if( $self->type eq q/bitvector/ ){ |
315
|
0
|
|
|
|
|
0
|
return $self->as_array($chromosome); |
316
|
|
|
|
|
|
|
}else{ |
317
|
0
|
|
|
|
|
0
|
my $ar = $self->as_array($chromosome); |
318
|
0
|
|
|
0
|
|
0
|
my $idx = first_index { $_ } @$ar; |
|
0
|
|
|
|
|
0
|
|
319
|
0
|
|
|
|
|
0
|
my @array = @$ar[$idx..$#$chromosome]; |
320
|
0
|
0
|
|
|
|
0
|
return @array if wantarray; |
321
|
0
|
|
|
|
|
0
|
return \@array; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
#======================================================================= |
325
|
|
|
|
|
|
|
sub as_array { |
326
|
14146
|
|
|
14146
|
1
|
68809
|
my ($self, $chromosome) = @_; |
327
|
|
|
|
|
|
|
|
328
|
14146
|
100
|
|
|
|
54108
|
if($self->type eq q/bitvector/){ |
|
|
100
|
|
|
|
|
|
329
|
11718
|
50
|
|
|
|
25551
|
return @$chromosome if wantarray; |
330
|
11718
|
|
|
|
|
35441
|
return $chromosome; |
331
|
|
|
|
|
|
|
}elsif($self->type eq q/rangevector/){ |
332
|
1084
|
|
|
|
|
2312
|
my $fix_range = $self->_fix_range; |
333
|
1084
|
|
|
|
|
1296
|
my $c = -1; |
334
|
|
|
|
|
|
|
#my @array = map { $c++; warn "WARN: $c | ",scalar @$chromosome,"\n" if not defined $fix_range->[$c]; $_ ? $_ - $fix_range->[$c] : undef } @$chromosome; |
335
|
1084
|
100
|
|
|
|
16371
|
my @array = map { $c++; $_ ? $_ - $fix_range->[$c] : undef } @$chromosome; |
|
8019
|
|
|
|
|
9764
|
|
|
8019
|
|
|
|
|
29948
|
|
336
|
|
|
|
|
|
|
|
337
|
1084
|
50
|
|
|
|
6512
|
return @array if wantarray; |
338
|
1084
|
|
|
|
|
4994
|
return \@array; |
339
|
|
|
|
|
|
|
}else{ |
340
|
1344
|
|
|
|
|
1710
|
my $cnt = 0; |
341
|
1344
|
|
|
|
|
20594
|
my @array = map { $self->_translations->[$cnt++]->[$_] } @$chromosome; |
|
9961
|
|
|
|
|
32179
|
|
342
|
1344
|
50
|
|
|
|
6200
|
return @array if wantarray; |
343
|
1344
|
|
|
|
|
5121
|
return \@array; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
#======================================================================= |
347
|
|
|
|
|
|
|
sub as_string_def_only { |
348
|
0
|
|
|
0
|
1
|
0
|
my ($self, $chromosome) = @_; |
349
|
|
|
|
|
|
|
|
350
|
0
|
0
|
0
|
|
|
0
|
return $self->as_string($chromosome) |
351
|
|
|
|
|
|
|
if not $self->variable_length or $self->variable_length < 2; |
352
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
0
|
my $array = $self->as_array_def_only($chromosome); |
354
|
|
|
|
|
|
|
|
355
|
0
|
0
|
|
|
|
0
|
return join(q//, @$array) if $self->type eq q/bitvector/; |
356
|
0
|
|
|
|
|
0
|
return join(q/___/, @$array); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
#======================================================================= |
359
|
|
|
|
|
|
|
sub as_string { |
360
|
414
|
50
|
|
414
|
1
|
5228
|
return join(q//, @{$_[1]}) if $_[0]->type eq q/bitvector/; |
|
414
|
|
|
|
|
15700
|
|
361
|
0
|
0
|
|
|
|
0
|
return join(q/___/, map { defined $_ ? $_ : q/ / } $_[0]->as_array($_[1])); |
|
0
|
|
|
|
|
0
|
|
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
#======================================================================= |
364
|
|
|
|
|
|
|
sub as_value { |
365
|
20044
|
|
|
20044
|
1
|
1610501
|
my ($self, $chromosome) = @_; |
366
|
20044
|
50
|
33
|
|
|
161889
|
croak(q/You MUST call 'as_value' as method of 'AI::Genetic::Pro' object./) |
|
|
|
33
|
|
|
|
|
367
|
|
|
|
|
|
|
unless defined $_[0] and ref $_[0] and ref $_[0] eq 'AI::Genetic::Pro'; |
368
|
20044
|
50
|
33
|
|
|
168154
|
croak(q/You MUST pass 'AI::Genetic::Pro::Chromosome' object to 'as_value' method./) |
|
|
|
33
|
|
|
|
|
369
|
|
|
|
|
|
|
unless defined $_[1] and ref $_[1] and ref $_[1] eq 'AI::Genetic::Pro::Chromosome'; |
370
|
20044
|
|
|
|
|
63938
|
return $self->fitness->($self, $chromosome); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
#======================================================================= |
373
|
|
|
|
|
|
|
# ALGORITHM ############################################################ |
374
|
|
|
|
|
|
|
#======================================================================= |
375
|
|
|
|
|
|
|
sub _calculate_fitness_all { |
376
|
15
|
|
|
15
|
|
39
|
my ($self) = @_; |
377
|
|
|
|
|
|
|
|
378
|
15
|
|
|
|
|
146
|
$self->_fitness( { } ); |
379
|
15
|
|
|
|
|
224
|
$self->_fitness->{$_} = $self->fitness()->($self, $self->chromosomes->[$_]) |
380
|
15
|
|
|
|
|
42
|
for 0..$#{$self->chromosomes}; |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# sorting the population is not necessary |
383
|
|
|
|
|
|
|
# my (@chromosomes, %fitness); |
384
|
|
|
|
|
|
|
# for my $idx (sort { $self->_fitness->{$a} <=> $self->_fitness->{$b} } keys %{$self->_fitness}){ |
385
|
|
|
|
|
|
|
# push @chromosomes, $self->chromosomes->[$idx]; |
386
|
|
|
|
|
|
|
# $fitness{$#chromosomes} = $self->_fitness->{$idx}; |
387
|
|
|
|
|
|
|
# delete $self->_fitness->{$idx}; |
388
|
|
|
|
|
|
|
# delete $self->chromosomes->[$idx]; |
389
|
|
|
|
|
|
|
# } |
390
|
|
|
|
|
|
|
# |
391
|
|
|
|
|
|
|
# $self->_fitness(\%fitness); |
392
|
|
|
|
|
|
|
# $self->chromosomes(\@chromosomes); |
393
|
|
|
|
|
|
|
|
394
|
15
|
|
|
|
|
494
|
return; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
#======================================================================= |
397
|
|
|
|
|
|
|
sub _select_parents { |
398
|
16
|
|
|
16
|
|
35
|
my ($self) = @_; |
399
|
16
|
100
|
|
|
|
160
|
unless($self->_selector){ |
400
|
10
|
50
|
|
|
|
116
|
croak "You must specify a selection strategy!" |
401
|
|
|
|
|
|
|
unless defined $self->selection; |
402
|
10
|
|
|
|
|
30
|
my @tmp = @{$self->selection}; |
|
10
|
|
|
|
|
57
|
|
403
|
10
|
|
|
|
|
57
|
my $selector = q/AI::Genetic::Pro::Selection::/ . shift @tmp; |
404
|
10
|
|
|
|
|
139
|
$selector->require; |
405
|
10
|
|
|
|
|
207
|
$self->_selector($selector->new(@tmp)); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
16
|
|
|
|
|
123
|
$self->_parents($self->_selector->run($self)); |
409
|
|
|
|
|
|
|
|
410
|
16
|
|
|
|
|
60
|
return; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
#======================================================================= |
413
|
|
|
|
|
|
|
sub _crossover { |
414
|
16
|
|
|
16
|
|
45
|
my ($self) = @_; |
415
|
|
|
|
|
|
|
|
416
|
16
|
100
|
|
|
|
126
|
unless($self->_strategist){ |
417
|
10
|
|
|
|
|
25
|
my @tmp = @{$self->strategy}; |
|
10
|
|
|
|
|
82
|
|
418
|
10
|
|
|
|
|
52
|
my $strategist = q/AI::Genetic::Pro::Crossover::/ . shift @tmp; |
419
|
10
|
|
|
|
|
146
|
$strategist->require; |
420
|
10
|
|
|
|
|
172
|
$self->_strategist($strategist->new(@tmp)); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
16
|
|
|
|
|
114
|
my $a = $self->_strategist->run($self); |
424
|
16
|
|
|
|
|
7289
|
$self->chromosomes( $a ); |
425
|
|
|
|
|
|
|
|
426
|
16
|
|
|
|
|
209
|
return; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
#======================================================================= |
429
|
|
|
|
|
|
|
sub _mutation { |
430
|
16
|
|
|
16
|
|
49
|
my ($self) = @_; |
431
|
|
|
|
|
|
|
|
432
|
16
|
100
|
|
|
|
297
|
unless($self->_mutator){ |
433
|
10
|
|
|
|
|
122
|
my $mutator = q/AI::Genetic::Pro::Mutation::/ . ucfirst(lc($self->type)); |
434
|
10
|
50
|
|
|
|
150
|
unless($mutator->require){ |
435
|
0
|
|
|
|
|
0
|
$mutator = q/AI::Genetic::Pro::Mutation::Listvector/; |
436
|
0
|
|
|
|
|
0
|
$mutator->require; |
437
|
|
|
|
|
|
|
} |
438
|
10
|
|
|
|
|
309
|
$self->_mutator($mutator->new); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
16
|
|
|
|
|
118
|
return $self->_mutator->run($self); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
#======================================================================= |
444
|
|
|
|
|
|
|
sub _save_history { |
445
|
16
|
|
|
16
|
|
33
|
my @tmp; |
446
|
16
|
50
|
|
|
|
111
|
if($_[0]->history){ @tmp = $_[0]->getAvgFitness; } |
|
0
|
|
|
|
|
0
|
|
447
|
16
|
|
|
|
|
60
|
else { @tmp = (undef, undef, undef); } |
448
|
|
|
|
|
|
|
|
449
|
16
|
|
|
|
|
35
|
push @{$_[0]->_history->[0]}, $tmp[0]; |
|
16
|
|
|
|
|
96
|
|
450
|
16
|
|
|
|
|
30
|
push @{$_[0]->_history->[1]}, $tmp[1]; |
|
16
|
|
|
|
|
73
|
|
451
|
16
|
|
|
|
|
36
|
push @{$_[0]->_history->[2]}, $tmp[2]; |
|
16
|
|
|
|
|
62
|
|
452
|
16
|
|
|
|
|
39
|
return 1; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
#======================================================================= |
455
|
|
|
|
|
|
|
sub inject { |
456
|
15
|
|
|
15
|
1
|
3755
|
my ($self, $candidates) = @_; |
457
|
|
|
|
|
|
|
|
458
|
15
|
|
|
|
|
49
|
for(@$candidates){ |
459
|
8783
|
|
|
|
|
12616
|
push @{$self->chromosomes}, |
|
8783
|
|
|
|
|
82554
|
|
460
|
|
|
|
|
|
|
AI::Genetic::Pro::Chromosome->new_from_data($self->_translations, $self->type, $self->_package, $_, $self->_fix_range); |
461
|
8783
|
|
|
|
|
50439
|
$self->_fitness->{$#{$self->chromosomes}} = $self->fitness()->($self, $self->chromosomes->[-1]); |
|
8783
|
|
|
|
|
81700
|
|
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
} |
464
|
15
|
|
|
|
|
97
|
$self->_strict( [ ] ); |
465
|
|
|
|
|
|
|
|
466
|
15
|
|
|
|
|
53
|
return 1; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
#======================================================================= |
469
|
|
|
|
|
|
|
sub evolve { |
470
|
12
|
|
|
12
|
1
|
80
|
my ($self, $generations) = @_; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# generations must be defined |
473
|
12
|
|
50
|
|
|
70
|
$generations ||= -1; |
474
|
|
|
|
|
|
|
|
475
|
12
|
50
|
33
|
|
|
193
|
if($self->strict and $self->_strict){ |
476
|
0
|
|
|
|
|
0
|
for my $idx (0..$#{$self->chromosomes}){ |
|
0
|
|
|
|
|
0
|
|
477
|
0
|
0
|
0
|
|
|
0
|
croak(q/Chromosomes was modified outside the 'evolve' function!/) unless $self->chromosomes->[$idx] and $self->_strict->[$idx]; |
478
|
0
|
|
|
|
|
0
|
my @tmp0 = @{$self->chromosomes->[$idx]}; |
|
0
|
|
|
|
|
0
|
|
479
|
0
|
|
|
|
|
0
|
my @tmp1 = @{$self->_strict->[$idx]}; |
|
0
|
|
|
|
|
0
|
|
480
|
0
|
0
|
|
|
|
0
|
croak(qq/Chromosome was modified outside the 'evolve' function from "@tmp0" to "@tmp1"!/) unless compare(\@tmp0, \@tmp1); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# split into two loops just for speed |
485
|
12
|
100
|
|
|
|
145
|
unless($self->preserve){ |
486
|
10
|
|
|
|
|
53
|
for(my $i = 0; $i != $generations; $i++){ |
487
|
|
|
|
|
|
|
# terminate ---------------------------------------------------- |
488
|
26
|
100
|
66
|
|
|
524
|
last if $self->terminate and $self->terminate->($self); |
489
|
|
|
|
|
|
|
# update generation -------------------------------------------- |
490
|
16
|
|
|
|
|
261
|
$self->generation($self->generation + 1); |
491
|
|
|
|
|
|
|
# update history ----------------------------------------------- |
492
|
16
|
|
|
|
|
72
|
$self->_save_history; |
493
|
|
|
|
|
|
|
# selection ---------------------------------------------------- |
494
|
16
|
|
|
|
|
68
|
$self->_select_parents(); |
495
|
|
|
|
|
|
|
# crossover ---------------------------------------------------- |
496
|
16
|
|
|
|
|
82
|
$self->_crossover(); |
497
|
|
|
|
|
|
|
# mutation ----------------------------------------------------- |
498
|
16
|
|
|
|
|
100
|
$self->_mutation(); |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
}else{ |
501
|
2
|
50
|
|
|
|
28
|
croak('You cannot preserve more chromosomes than is in population!') if $self->preserve > $self->population; |
502
|
2
|
|
|
|
|
4
|
my @preserved; |
503
|
2
|
|
|
|
|
10
|
for(my $i = 0; $i != $generations; $i++){ |
504
|
|
|
|
|
|
|
# terminate ---------------------------------------------------- |
505
|
2
|
50
|
33
|
|
|
41
|
last if $self->terminate and $self->terminate->($self); |
506
|
|
|
|
|
|
|
# update generation -------------------------------------------- |
507
|
0
|
|
|
|
|
0
|
$self->generation($self->generation + 1); |
508
|
|
|
|
|
|
|
# update history ----------------------------------------------- |
509
|
0
|
|
|
|
|
0
|
$self->_save_history; |
510
|
|
|
|
|
|
|
#--------------------------------------------------------------- |
511
|
|
|
|
|
|
|
# preservation of N unique chromosomes |
512
|
0
|
|
|
|
|
0
|
@preserved = map { clone($_) } @{ $self->getFittest_as_arrayref($self->preserve - 1, 1) }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
513
|
|
|
|
|
|
|
# selection ---------------------------------------------------- |
514
|
0
|
|
|
|
|
0
|
$self->_select_parents(); |
515
|
|
|
|
|
|
|
# crossover ---------------------------------------------------- |
516
|
0
|
|
|
|
|
0
|
$self->_crossover(); |
517
|
|
|
|
|
|
|
# mutation ----------------------------------------------------- |
518
|
0
|
|
|
|
|
0
|
$self->_mutation(); |
519
|
|
|
|
|
|
|
#--------------------------------------------------------------- |
520
|
0
|
|
|
|
|
0
|
for(@preserved){ |
521
|
0
|
|
|
|
|
0
|
my $idx = int rand @{$self->chromosomes}; |
|
0
|
|
|
|
|
0
|
|
522
|
0
|
|
|
|
|
0
|
$self->chromosomes->[$idx] = $_; |
523
|
0
|
|
|
|
|
0
|
$self->_fitness->{$idx} = $self->fitness()->($self, $_); |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
12
|
50
|
|
|
|
248
|
if($self->strict){ |
529
|
0
|
|
|
|
|
0
|
$self->_strict( [ ] ); |
530
|
0
|
|
|
|
|
0
|
push @{$self->_strict}, clone($_) for @{$self->chromosomes}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
#======================================================================= |
534
|
|
|
|
|
|
|
# ALIASES ############################################################## |
535
|
|
|
|
|
|
|
#======================================================================= |
536
|
0
|
|
|
0
|
1
|
0
|
sub people { $_[0]->chromosomes() } |
537
|
|
|
|
|
|
|
#======================================================================= |
538
|
0
|
|
|
0
|
1
|
0
|
sub getHistory { $_[0]->_history() } |
539
|
|
|
|
|
|
|
#======================================================================= |
540
|
0
|
|
|
0
|
1
|
0
|
sub mutProb { shift->mutation(@_) } |
541
|
|
|
|
|
|
|
#======================================================================= |
542
|
0
|
|
|
0
|
1
|
0
|
sub crossProb { shift->crossover(@_) } |
543
|
|
|
|
|
|
|
#======================================================================= |
544
|
0
|
|
|
0
|
0
|
0
|
sub intType { shift->type() } |
545
|
|
|
|
|
|
|
#======================================================================= |
546
|
|
|
|
|
|
|
# STATS ################################################################ |
547
|
|
|
|
|
|
|
#======================================================================= |
548
|
|
|
|
|
|
|
sub getFittest_as_arrayref { |
549
|
39
|
|
|
39
|
1
|
138
|
my ($self, $n, $uniq) = @_; |
550
|
39
|
|
100
|
|
|
234
|
$n ||= 1; |
551
|
|
|
|
|
|
|
|
552
|
39
|
50
|
|
|
|
68
|
$self->_calculate_fitness_all() unless scalar %{ $self->_fitness }; |
|
39
|
|
|
|
|
242
|
|
553
|
39
|
|
|
|
|
102
|
my @keys = sort { $self->_fitness->{$a} <=> $self->_fitness->{$b} } 0..$#{$self->chromosomes}; |
|
154972
|
|
|
|
|
540067
|
|
|
39
|
|
|
|
|
4219
|
|
554
|
|
|
|
|
|
|
|
555
|
39
|
50
|
|
|
|
3249
|
if($uniq){ |
556
|
0
|
|
|
|
|
0
|
my %grep; |
557
|
0
|
|
|
|
|
0
|
my $chromosomes = $self->chromosomes; |
558
|
0
|
|
|
|
|
0
|
@keys = grep { |
559
|
0
|
|
|
|
|
0
|
my $add_to_list = 0; |
560
|
0
|
|
|
|
|
0
|
my $key = md5_hex(${tied(@{$chromosomes->[$_]})}); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
561
|
0
|
0
|
|
|
|
0
|
unless($grep{$key}) { |
562
|
0
|
|
|
|
|
0
|
$grep{$key} = 1; |
563
|
0
|
|
|
|
|
0
|
$add_to_list = 1; |
564
|
|
|
|
|
|
|
} |
565
|
0
|
|
|
|
|
0
|
$add_to_list; |
566
|
|
|
|
|
|
|
} @keys; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
39
|
50
|
|
|
|
302
|
$n = scalar @keys if $n > scalar @keys; |
570
|
39
|
|
|
|
|
395
|
return [ reverse @{$self->chromosomes}[ splice @keys, $#keys - $n + 1, $n ] ]; |
|
39
|
|
|
|
|
3996
|
|
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
#======================================================================= |
573
|
39
|
50
|
|
39
|
1
|
394
|
sub getFittest { return wantarray ? @{ shift->getFittest_as_arrayref(@_) } : shift @{ shift->getFittest_as_arrayref(@_) }; } |
|
39
|
|
|
|
|
188
|
|
|
0
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
#======================================================================= |
575
|
|
|
|
|
|
|
sub getAvgFitness { |
576
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
577
|
|
|
|
|
|
|
|
578
|
0
|
|
|
|
|
|
my @minmax = minmax values %{$self->_fitness}; |
|
0
|
|
|
|
|
|
|
579
|
0
|
|
|
|
|
|
my $mean = sum(values %{$self->_fitness}) / scalar values %{$self->_fitness}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
580
|
0
|
|
|
|
|
|
return $minmax[1], int($mean), $minmax[0]; |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
#======================================================================= |
583
|
|
|
|
|
|
|
1; |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
__END__ |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=head1 NAME |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
AI::Genetic::Pro - Efficient genetic algorithms for professional purpose. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=head1 SYNOPSIS |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
use AI::Genetic::Pro; |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub fitness { |
597
|
|
|
|
|
|
|
my ($ga, $chromosome) = @_; |
598
|
|
|
|
|
|
|
return oct('0b' . $ga->as_string($chromosome)); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub terminate { |
602
|
|
|
|
|
|
|
my ($ga) = @_; |
603
|
|
|
|
|
|
|
my $result = oct('0b' . $ga->as_string($ga->getFittest)); |
604
|
|
|
|
|
|
|
return $result == 4294967295 ? 1 : 0; |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
my $ga = AI::Genetic::Pro->new( |
608
|
|
|
|
|
|
|
-fitness => \&fitness, # fitness function |
609
|
|
|
|
|
|
|
-terminate => \&terminate, # terminate function |
610
|
|
|
|
|
|
|
-type => 'bitvector', # type of chromosomes |
611
|
|
|
|
|
|
|
-population => 1000, # population |
612
|
|
|
|
|
|
|
-crossover => 0.9, # probab. of crossover |
613
|
|
|
|
|
|
|
-mutation => 0.01, # probab. of mutation |
614
|
|
|
|
|
|
|
-parents => 2, # number of parents |
615
|
|
|
|
|
|
|
-selection => [ 'Roulette' ], # selection strategy |
616
|
|
|
|
|
|
|
-strategy => [ 'Points', 2 ], # crossover strategy |
617
|
|
|
|
|
|
|
-cache => 0, # cache results |
618
|
|
|
|
|
|
|
-history => 1, # remember best results |
619
|
|
|
|
|
|
|
-preserve => 3, # remember the bests |
620
|
|
|
|
|
|
|
-variable_length => 1, # turn variable length ON |
621
|
|
|
|
|
|
|
); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# init population of 32-bit vectors |
624
|
|
|
|
|
|
|
$ga->init(32); |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
# evolve 10 generations |
627
|
|
|
|
|
|
|
$ga->evolve(10); |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
# best score |
630
|
|
|
|
|
|
|
print "SCORE: ", $ga->as_value($ga->getFittest), ".\n"; |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# save evolution path as a chart |
633
|
|
|
|
|
|
|
$ga->chart(-filename => 'evolution.png'); |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
# save state of GA |
636
|
|
|
|
|
|
|
$ga->save('genetic.sga'); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# load state of GA |
639
|
|
|
|
|
|
|
$ga->load('genetic.sga'); |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head1 DESCRIPTION |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
This module provides efficient implementation of a genetic algorithm for |
644
|
|
|
|
|
|
|
professional use. It was designed to operate as fast as possible |
645
|
|
|
|
|
|
|
even on very large populations and big individuals/chromosomes. C<AI::Genetic::Pro> |
646
|
|
|
|
|
|
|
was inspired by C<AI::Genetic>, so it is in most cases compatible |
647
|
|
|
|
|
|
|
(there are some changes). Additionally C<AI::Genetic::Pro> isn't a pure Perl solution, so it |
648
|
|
|
|
|
|
|
B<doesn't have> limitations of its ancestor (such as serious slow-down in the |
649
|
|
|
|
|
|
|
case of big populations ( >10000 ) or vectors with more than 33 fields). |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
If You are looking for a pure Perl solution, consider L<AI::Genetic>. |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=over 4 |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=item Speed |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
To increase speed XS code is used, however with portability in |
658
|
|
|
|
|
|
|
mind. This distribution was tested on Windows and Linux platforms |
659
|
|
|
|
|
|
|
(and should work on any other). |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item Memory |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
This module was designed to use as little memory as possible. A population |
664
|
|
|
|
|
|
|
of size 10000 consisting of 92-bit vectors uses only ~24MB (C<AI::Genetic> |
665
|
|
|
|
|
|
|
would use about 78MB!). |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=item Advanced options |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
To provide more flexibility C<AI::Genetic::Pro> supports many |
670
|
|
|
|
|
|
|
statistical distributions, such as C<uniform>, C<natural>, C<chi_square> |
671
|
|
|
|
|
|
|
and others. This feature can be used in selection and/or crossover. See |
672
|
|
|
|
|
|
|
the documentation below. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=back |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=head1 METHODS |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=over 4 |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<new>( %options ) |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
Constructor. It accepts options in hash-value style. See options and |
683
|
|
|
|
|
|
|
an example below. |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=over 8 |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
=item -fitness |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
This defines a I<fitness> function. It expects a reference to a subroutine. |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=item -terminate |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
This defines a I<terminate> function. It expects a reference to a subroutine. |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=item -type |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
This defines the type of chromosomes. Currently, C<AI::Genetic::Pro> supports four types: |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=over 12 |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=item bitvector |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
Individuals/chromosomes of this type have genes that are bits. Each gene can be in one of two possible states, on or off. |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=item listvector |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
Each gene of a "listvector" individual/chromosome can assume one string value from a specified list of possible string values. |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=item rangevector |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
Each gene of a "rangevector" individual/chromosome can assume one integer |
712
|
|
|
|
|
|
|
value from a range of possible integer values. Note that only integers |
713
|
|
|
|
|
|
|
are supported. The user can always transform any desired fractional values |
714
|
|
|
|
|
|
|
by multiplying and dividing by an appropriate power of 10. |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=item combination |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
Each gene of a "combination" individual/chromosome can assume one string value from a specified list of possible string values. B<All genes are unique.> |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=back |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=item -population |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
This defines the size of the population, i.e. how many chromosomes |
725
|
|
|
|
|
|
|
simultaneously exist at each generation. |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=item -crossover |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
This defines the crossover rate. The fairest results are achieved with |
730
|
|
|
|
|
|
|
crossover rate ~0.95. |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=item -mutation |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
This defines the mutation rate. The fairest results are achieved with mutation |
735
|
|
|
|
|
|
|
rate ~0.01. |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=item -preserve |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
This defines injection of the bests chromosomes into a next generation. It causes a little slow down, however (very often) much better results are achieved. You can specify, how many chromosomes will be preserved, i.e. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
-preserve => 1, # only one chromosome will be preserved |
742
|
|
|
|
|
|
|
# or |
743
|
|
|
|
|
|
|
-preserve => 9, # 9 chromosomes will be preserved |
744
|
|
|
|
|
|
|
# and so on... |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
Attention! You cannot preserve more chromosomes than exist in your population. |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item -variable_length |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
This defines whether variable-length chromosomes are turned on (default off) |
751
|
|
|
|
|
|
|
and a which types of mutation are allowed. See below. |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=over 8 |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
=item level 0 |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
Feature is inactive (default). Example: |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
-variable_length => 0 |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# chromosomes (i.e. bitvectors) |
762
|
|
|
|
|
|
|
0 1 0 0 1 1 0 1 1 1 0 1 0 1 |
763
|
|
|
|
|
|
|
0 0 1 1 0 1 1 1 1 0 0 1 1 0 |
764
|
|
|
|
|
|
|
0 1 1 1 0 1 0 0 1 1 0 1 1 1 |
765
|
|
|
|
|
|
|
0 1 0 0 1 1 0 1 1 1 1 0 1 0 |
766
|
|
|
|
|
|
|
# ...and so on |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=item level 1 |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
Feature is active, but chromosomes can varies B<only on the right side>, Example: |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
-variable_length => 1 |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
# chromosomes (i.e. bitvectors) |
775
|
|
|
|
|
|
|
0 1 0 0 1 1 0 1 1 1 |
776
|
|
|
|
|
|
|
0 0 1 1 0 1 1 1 1 |
777
|
|
|
|
|
|
|
0 1 1 1 0 1 0 0 1 1 0 1 1 1 |
778
|
|
|
|
|
|
|
0 1 0 0 1 1 0 1 1 1 |
779
|
|
|
|
|
|
|
# ...and so on |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=item level 2 |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
Feature is active and chromosomes can varies B<on the left side and on |
784
|
|
|
|
|
|
|
the right side>; unwanted values/genes on the left side are replaced with C<undef>, ie. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
-variable_length => 2 |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
# chromosomes (i.e. bitvectors) |
789
|
|
|
|
|
|
|
x x x 0 1 1 0 1 1 1 |
790
|
|
|
|
|
|
|
x x x x 0 1 1 1 1 |
791
|
|
|
|
|
|
|
x 1 1 1 0 1 0 0 1 1 0 1 1 1 |
792
|
|
|
|
|
|
|
0 1 0 0 1 1 0 1 1 1 |
793
|
|
|
|
|
|
|
# where 'x' means 'undef' |
794
|
|
|
|
|
|
|
# ...and so on |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
In this situation returned chromosomes in an array context ($ga-E<gt>as_array($chromosome)) |
797
|
|
|
|
|
|
|
can have B<undef> values on the left side (only). In a scalar context each |
798
|
|
|
|
|
|
|
undefined value is replaced with a single space. If You don't want to see |
799
|
|
|
|
|
|
|
any C<undef> or space, just use C<as_array_def_only> and C<as_string_def_only> |
800
|
|
|
|
|
|
|
instead of C<as_array> and C<as_string>. |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
=back |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
=item -parents |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
This defines how many parents should be used in a crossover. |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
=item -selection |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
This defines how individuals/chromosomes are selected to crossover. It expects an array reference listed below: |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
-selection => [ $type, @params ] |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
where type is one of: |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=over 8 |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=item B<RouletteBasic> |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
Each individual/chromosome can be selected with probability proportional to its fitness. |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=item B<Roulette> |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
First the best individuals/chromosomes are selected. From this collection |
825
|
|
|
|
|
|
|
parents are selected with probability poportional to their fitness. |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=item B<RouletteDistribution> |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
Each individual/chromosome has a portion of roulette wheel proportional to its |
830
|
|
|
|
|
|
|
fitness. Selection is done with the specified distribution. Supported |
831
|
|
|
|
|
|
|
distributions and parameters are listed below. |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=over 12 |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'uniform' ]> |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
Standard uniform distribution. No additional parameters are needed. |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'normal', $av, $sd ]> |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
Normal distribution, where C<$av> is average (default: size of population /2) and $C<$sd> is standard deviation (default: size of population). |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'beta', $aa, $bb ]> |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
I<Beta> distribution. The density of the beta is: |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
X^($aa - 1) * (1 - X)^($bb - 1) / B($aa , $bb) for 0 < X < 1. |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
C<$aa> and C<$bb> are set by default to number of parents. |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
B<Argument restrictions:> Both $aa and $bb must not be less than 1.0E-37. |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'binomial' ]> |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
Binomial distribution. No additional parameters are needed. |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'chi_square', $df ]> |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
Chi-square distribution with C<$df> degrees of freedom. C<$df> by default is set to size of population. |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'exponential', $av ]> |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
Exponential distribution, where C<$av> is average . C<$av> by default is set to size of population. |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'RouletteDistribution', 'poisson', $mu ]> |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
Poisson distribution, where C<$mu> is mean. C<$mu> by default is set to size of population. |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=back |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=item B<Distribution> |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Chromosomes/individuals are selected with specified distribution. See below. |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=over 12 |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'uniform' ]> |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
Standard uniform distribution. No additional parameters are needed. |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'normal', $av, $sd ]> |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
Normal distribution, where C<$av> is average (default: size of population /2) and $C<$sd> is standard deviation (default: size of population). |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'beta', $aa, $bb ]> |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
I<Beta> distribution. The density of the beta is: |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
X^($aa - 1) * (1 - X)^($bb - 1) / B($aa , $bb) for 0 < X < 1. |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
C<$aa> and C<$bb> are set by default to number of parents. |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
B<Argument restrictions:> Both $aa and $bb must not be less than 1.0E-37. |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'binomial' ]> |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
Binomial distribution. No additional parameters are needed. |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'chi_square', $df ]> |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
Chi-square distribution with C<$df> degrees of freedom. C<$df> by default is set to size of population. |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'exponential', $av ]> |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
Exponential distribution, where C<$av> is average . C<$av> by default is set to size of population. |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=item C<-selection =E<gt> [ 'Distribution', 'poisson', $mu ]> |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
Poisson distribution, where C<$mu> is mean. C<$mu> by default is set to size of population. |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=back |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=back |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=item -strategy |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
This defines the astrategy of crossover operation. It expects an array |
919
|
|
|
|
|
|
|
reference listed below: |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
-strategy => [ $type, @params ] |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
where type is one of: |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=over 4 |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
=item PointsSimple |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
Simple crossover in one or many points. The best chromosomes/individuals are |
930
|
|
|
|
|
|
|
selected for the new generation. For example: |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
-strategy => [ 'PointsSimple', $n ] |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
where C<$n> is the number of points for crossing. |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
=item PointsBasic |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
Crossover in one or many points. In basic crossover selected parents are |
939
|
|
|
|
|
|
|
crossed and one (randomly-chosen) child is moved to the new generation. For |
940
|
|
|
|
|
|
|
example: |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
-strategy => [ 'PointsBasic', $n ] |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
where C<$n> is the number of points for crossing. |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
=item Points |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
Crossover in one or many points. In normal crossover selected parents are crossed and the best child is moved to the new generation. For example: |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
-strategy => [ 'Points', $n ] |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
where C<$n> is number of points for crossing. |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
=item PointsAdvenced |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
Crossover in one or many points. After crossover the best |
957
|
|
|
|
|
|
|
chromosomes/individuals from all parents and chidren are selected for the new |
958
|
|
|
|
|
|
|
generation. For example: |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
-strategy => [ 'PointsAdvanced', $n ] |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
where C<$n> is the number of points for crossing. |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
=item Distribution |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
In I<distribution> crossover parents are crossed in points selected with the |
967
|
|
|
|
|
|
|
specified distribution. See below. |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=over 8 |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'uniform' ]> |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
Standard uniform distribution. No additional parameters are needed. |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'normal', $av, $sd ]> |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
Normal distribution, where C<$av> is average (default: number of parents/2) and C<$sd> is standard deviation (default: number of parents). |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'beta', $aa, $bb ]> |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
I<Beta> distribution. The density of the beta is: |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
X^($aa - 1) * (1 - X)^($bb - 1) / B($aa , $bb) for 0 < X < 1. |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
C<$aa> and C<$bb> are set by default to the number of parents. |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
B<Argument restrictions:> Both $aa and $bb must not be less than 1.0E-37. |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'binomial' ]> |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
Binomial distribution. No additional parameters are needed. |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'chi_square', $df ]> |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
Chi-squared distribution with C<$df> degrees of freedom. C<$df> by default is set to the number of parents. |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'exponential', $av ]> |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
Exponential distribution, where C<$av> is average . C<$av> by default is set to the number of parents. |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
=item C<-strategy =E<gt> [ 'Distribution', 'poisson', $mu ]> |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
Poisson distribution, where C<$mu> is mean. C<$mu> by default is set to the number of parents. |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
=back |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
=item PMX |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
PMX method defined by Goldberg and Lingle in 1985. Parameters: I<none>. |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=item OX |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
OX method defined by Davis (?) in 1985. Parameters: I<none>. |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
=back |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
=item -cache |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
This defines whether a cache should be used. Allowed values are 1 or 0 |
1020
|
|
|
|
|
|
|
(default: I<0>). |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=item -history |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
This defines whether history should be collected. Allowed values are 1 or 0 (default: I<0>). |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=item -strict |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
This defines if the check for modifying chromosomes in a user-defined fitness |
1029
|
|
|
|
|
|
|
function is active. Directly modifying chromosomes is not allowed and it is |
1030
|
|
|
|
|
|
|
a highway to big trouble. This mode should be used only for testing, because it is B<slow>. |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
=back |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<inject>($chromosomes) |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
Inject new, user defined, chromosomes into the current population. See example below: |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
# example for bitvector |
1039
|
|
|
|
|
|
|
my $chromosomes = [ |
1040
|
|
|
|
|
|
|
[ 1, 1, 0, 1, 0, 1 ], |
1041
|
|
|
|
|
|
|
[ 0, 0, 0, 1, 0, 1 ], |
1042
|
|
|
|
|
|
|
[ 0, 1, 0, 1, 0, 0 ], |
1043
|
|
|
|
|
|
|
... |
1044
|
|
|
|
|
|
|
]; |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
# inject |
1047
|
|
|
|
|
|
|
$ga->inject($chromosomes); |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
If You want to delete some chromosomes from population, just C<splice> them: |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
my @remove = qw(1 2 3 9 12); |
1052
|
|
|
|
|
|
|
for my $idx (sort { $b <=> $a } @remove){ |
1053
|
|
|
|
|
|
|
splice @{$ga->chromosomes}, $idx, 1; |
1054
|
|
|
|
|
|
|
} |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<population>($population) |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
Set/get size of the population. This defines the size of the population, i.e. how many chromosomes to simultaneously exist at each generation. |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<indType>() |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
Get type of individuals/chromosomes. Currently supported types are: |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
=over 4 |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
=item C<bitvector> |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
Chromosomes will be just bitvectors. See documentation of C<new> method. |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
=item C<listvector> |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
Chromosomes will be lists of specified values. See documentation of C<new> method. |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
=item C<rangevector> |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
Chromosomes will be lists of values from specified range. See documentation of C<new> method. |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
=item C<combination> |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
Chromosomes will be unique lists of specified values. This is used for example |
1081
|
|
|
|
|
|
|
in the I<Traveling Salesman Problem>. See the documentation of the C<new> |
1082
|
|
|
|
|
|
|
method. |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
=back |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
In example: |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
my $type = $ga->type(); |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<type>() |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
Alias for C<indType>. |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<crossProb>() |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
This method is used to query and set the crossover rate. |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<crossover>() |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
Alias for C<crossProb>. |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<mutProb>() |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
This method is used to query and set the mutation rate. |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<mutation>() |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
Alias for C<mutProb>. |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<parents>($parents) |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
Set/get number of parents in a crossover. |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<init>($args) |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
This method initializes the population with random individuals/chromosomes. It MUST be called before any call to C<evolve()>. It expects one argument, which depends on the type of individuals/chromosomes: |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
=over 4 |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
=item B<bitvector> |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
For bitvectors, the argument is simply the length of the bitvector. |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
$ga->init(10); |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
This initializes a population where each individual/chromosome has 10 genes. |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
=item B<listvector> |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
For listvectors, the argument is an anonymous list of lists. The number of sub-lists is equal to the number of genes of each individual/chromosome. Each sub-list defines the possible string values that the corresponding gene can assume. |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
$ga->init([ |
1133
|
|
|
|
|
|
|
[qw/red blue green/], |
1134
|
|
|
|
|
|
|
[qw/big medium small/], |
1135
|
|
|
|
|
|
|
[qw/very_fat fat fit thin very_thin/], |
1136
|
|
|
|
|
|
|
]); |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
This initializes a population where each individual/chromosome has 3 genes and each gene can assume one of the given values. |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
=item B<rangevector> |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
For rangevectors, the argument is an anonymous list of lists. The number of sub-lists is equal to the number of genes of each individual/chromosome. Each sub-list defines the minimum and maximum integer values that the corresponding gene can assume. |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
$ga->init([ |
1145
|
|
|
|
|
|
|
[1, 5], |
1146
|
|
|
|
|
|
|
[0, 20], |
1147
|
|
|
|
|
|
|
[4, 9], |
1148
|
|
|
|
|
|
|
]); |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
This initializes a population where each individual/chromosome has 3 genes and each gene can assume an integer within the corresponding range. |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
=item B<combination> |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
For combination, the argument is an anonymous list of possible values of gene. |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
$ga->init( [ 'a', 'b', 'c' ] ); |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
This initializes a population where each chromosome has 3 genes and each gene |
1159
|
|
|
|
|
|
|
is a unique combination of 'a', 'b' and 'c'. For example genes looks something |
1160
|
|
|
|
|
|
|
like that: |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
[ 'a', 'b', 'c' ] # gene 1 |
1163
|
|
|
|
|
|
|
[ 'c', 'a', 'b' ] # gene 2 |
1164
|
|
|
|
|
|
|
[ 'b', 'c', 'a' ] # gene 3 |
1165
|
|
|
|
|
|
|
# ...and so on... |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
=back |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<evolve>($n) |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
This method causes the GA to evolve the population for the specified number of |
1172
|
|
|
|
|
|
|
generations. If its argument is 0 or C<undef> GA will evolve the population to |
1173
|
|
|
|
|
|
|
infinity unless a C<terminate> function is specified. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<getHistory>() |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
Get history of the evolution. It is in a format listed below: |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
[ |
1180
|
|
|
|
|
|
|
# gen0 gen1 gen2 ... # generations |
1181
|
|
|
|
|
|
|
[ max0, max1, max2, ... ], # max values |
1182
|
|
|
|
|
|
|
[ mean, mean1, mean2, ... ], # mean values |
1183
|
|
|
|
|
|
|
[ min0, min1, min2, ... ], # min values |
1184
|
|
|
|
|
|
|
] |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<getAvgFitness>() |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
Get I<max>, I<mean> and I<min> score of the current generation. In example: |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
my ($max, $mean, $min) = $ga->getAvgFitness(); |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<getFittest>($n, $unique) |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
This function returns a list of the fittest chromosomes from the current |
1195
|
|
|
|
|
|
|
population. You can specify how many chromosomes should be returned and if |
1196
|
|
|
|
|
|
|
the returned chromosomes should be unique. See example below. |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
# only one - the best |
1199
|
|
|
|
|
|
|
my ($best) = $ga->getFittest; |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
# or 5 bests chromosomes, NOT unique |
1202
|
|
|
|
|
|
|
my @bests = $ga->getFittest(5); |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
# or 7 bests and UNIQUE chromosomes |
1205
|
|
|
|
|
|
|
my @bests = $ga->getFittest(7, 1); |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
If you want to get a large number of chromosomes, try to use the |
1208
|
|
|
|
|
|
|
C<getFittest_as_arrayref> function instead (for efficiency). |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<getFittest_as_arrayref>($n, $unique) |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
This function is very similar to C<getFittest>, but it returns a reference |
1213
|
|
|
|
|
|
|
to an array instead of a list. |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<generation>() |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
Get the number of the current generation. |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<people>() |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
Returns an anonymous list of individuals/chromosomes of the current population. |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
B<IMPORTANT:> the actual array reference used by the C<AI::Genetic::Pro> |
1224
|
|
|
|
|
|
|
object is returned, so any changes to it will be reflected in I<$ga>. |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<chromosomes>() |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
Alias for C<people>. |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<chart>(%options) |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
Generate a chart describing changes of min, mean, and max scores in your |
1233
|
|
|
|
|
|
|
population. To satisfy your needs, you can pass the following options: |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
=over 4 |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
=item -filename |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
File to save a chart in (B<obligatory>). |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
=item -title |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
Title of a chart (default: I<Evolution>). |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
=item -x_label |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
X label (default: I<Generations>). |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
=item -y_label |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
Y label (default: I<Value>). |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
=item -format |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
Format of values, like C<sprintf> (default: I<'%.2f'>). |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
=item -legend1 |
1258
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
Description of min line (default: I<Min value>). |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
=item -legend2 |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
Description of min line (default: I<Mean value>). |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
=item -legend3 |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
Description of min line (default: I<Max value>). |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=item -width |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
Width of a chart (default: I<640>). |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
=item -height |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
Height of a chart (default: I<480>). |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
=item -font |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
Path to font (in *.ttf format) to be used (default: none). |
1280
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
=item -logo |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
Path to logo (png/jpg image) to embed in a chart (default: none). |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=item For example: |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
$ga->chart(-width => 480, height => 320, -filename => 'chart.png'); |
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
=back |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<save>($file) |
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
Save the current state of the genetic algorithm to the specified file. |
1294
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<load>($file) |
1296
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
Load a state of the genetic algorithm from the specified file. |
1298
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<as_array>($chromosome) |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
In list context return an array representing the specified chromosome. |
1302
|
|
|
|
|
|
|
In scalar context return an reference to an array representing the specified |
1303
|
|
|
|
|
|
|
chromosome. If I<variable_length> is turned on and is set to level 2, an array |
1304
|
|
|
|
|
|
|
can have some C<undef> values. To get only C<not undef> values use |
1305
|
|
|
|
|
|
|
C<as_array_def_only> instead of C<as_array>. |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<as_array_def_only>($chromosome) |
1308
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
In list context return an array representing the specified chromosome. |
1310
|
|
|
|
|
|
|
In scalar context return an reference to an array representing the specified |
1311
|
|
|
|
|
|
|
chromosome. If I<variable_length> is turned off, this function is just an |
1312
|
|
|
|
|
|
|
alias for C<as_array>. If I<variable_length> is turned on and is set to |
1313
|
|
|
|
|
|
|
level 2, this function will return only C<not undef> values from chromosome. |
1314
|
|
|
|
|
|
|
See example below: |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
# -variable_length => 2, -type => 'bitvector' |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
my @chromosome = $ga->as_array($chromosome) |
1319
|
|
|
|
|
|
|
# @chromosome looks something like that |
1320
|
|
|
|
|
|
|
# ( undef, undef, undef, 1, 0, 1, 1, 1, 0 ) |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
@chromosome = $ga->as_array_def_only($chromosome) |
1323
|
|
|
|
|
|
|
# @chromosome looks something like that |
1324
|
|
|
|
|
|
|
# ( 1, 0, 1, 1, 1, 0 ) |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<as_string>($chromosome) |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
Return a string representation of the specified chromosome. See example below: |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
# -type => 'bitvector' |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
my $string = $ga->as_string($chromosome); |
1333
|
|
|
|
|
|
|
# $string looks something like that |
1334
|
|
|
|
|
|
|
# 1___0___1___1___1___0 |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
# or |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
# -type => 'listvector' |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
$string = $ga->as_string($chromosome); |
1341
|
|
|
|
|
|
|
# $string looks something like that |
1342
|
|
|
|
|
|
|
# element0___element1___element2___element3... |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
Attention! If I<variable_length> is turned on and is set to level 2, it is |
1345
|
|
|
|
|
|
|
possible to get C<undef> values on the left side of the vector. In the returned |
1346
|
|
|
|
|
|
|
string C<undef> values will be replaced with B<spaces>. If you don't want |
1347
|
|
|
|
|
|
|
to see any I<spaces>, use C<as_string_def_only> instead of C<as_string>. |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<as_string_def_only>($chromosome) |
1350
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
Return a string representation of specified chromosome. If I<variable_length> |
1352
|
|
|
|
|
|
|
is turned off, this function is just alias for C<as_string>. If I<variable_length> |
1353
|
|
|
|
|
|
|
is turned on and is set to level 2, this function will return a string without |
1354
|
|
|
|
|
|
|
C<undef> values. See example below: |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
# -variable_length => 2, -type => 'bitvector' |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
my $string = $ga->as_string($chromosome); |
1359
|
|
|
|
|
|
|
# $string looks something like that |
1360
|
|
|
|
|
|
|
# ___ ___ ___1___1___0 |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
$string = $ga->as_string_def_only($chromosome); |
1363
|
|
|
|
|
|
|
# $string looks something like that |
1364
|
|
|
|
|
|
|
# 1___1___0 |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
=item I<$ga>-E<gt>B<as_value>($chromosome) |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
Return the score of the specified chromosome. The value of I<chromosome> is |
1369
|
|
|
|
|
|
|
calculated by the fitness function. |
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
=back |
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
=head1 SUPPORT |
1374
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
C<AI::Genetic::Pro> is still under development; however, it is used in many |
1376
|
|
|
|
|
|
|
production environments. |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
=head1 TODO |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=over 4 |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
=item Examples. |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
=item More tests. |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
=item More warnings about incorrect parameters. |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
=back |
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
=head1 REPORTING BUGS |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
When reporting bugs/problems please include as much information as possible. |
1393
|
|
|
|
|
|
|
It may be difficult for me to reproduce the problem as almost every setup |
1394
|
|
|
|
|
|
|
is different. |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
A small script which yields the problem will probably be of help. |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
=head1 THANKS |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
Miles Gould for suggestions and some fixes (even in this documentation! :-). |
1401
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
Alun Jones for fixing memory leaks. |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
Tod Hagan for reporting a bug (rangevector values truncated to signed 8-bit quantities) and supplying a patch. |
1405
|
|
|
|
|
|
|
|
1406
|
|
|
|
|
|
|
Randal L. Schwartz for reporting a bug in this documentation. |
1407
|
|
|
|
|
|
|
|
1408
|
|
|
|
|
|
|
Maciej Misiak for reporting problems with C<combination> (and a bug in a PMX strategy). |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
LEONID ZAMDBORG for recommending the addition of variable-length chromosomes as well as supplying relevant code samples, for testing and at the end reporting some bugs. |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
Christoph Meissner for reporting a bug. |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
Alec Chen for reporting some bugs. |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
=head1 AUTHOR |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
Strzelecki Lukasz <lukasz@strzeleccy.eu> |
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
=head1 SEE ALSO |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
L<AI::Genetic> |
1423
|
|
|
|
|
|
|
L<Algorithm::Evolutionary> |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1426
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
Copyright (c) Strzelecki Lukasz. All rights reserved. |
1428
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
1429
|
|
|
|
|
|
|
under the same terms as Perl itself. |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
=cut |