File Coverage

blib/lib/AI/Genetic/Pro.pm
Criterion Covered Total %
statement 228 360 63.3
branch 70 144 48.6
condition 20 70 28.5
subroutine 36 51 70.5
pod 19 20 95.0
total 373 645 57.8


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