File Coverage

lib/Algorithm/MasterMind/EDA.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package Algorithm::MasterMind::EDA;
2              
3 2     2   815 use warnings;
  2         4  
  2         62  
4 2     2   10 use strict;
  2         5  
  2         56  
5 2     2   8 use Carp;
  2         4  
  2         105  
6              
7 2         11 use lib qw(../../lib
8             ../../../lib
9             ../../../../Algorithm-Evolutionary/lib
10             ../../../Algorithm-Evolutionary/lib
11 2     2   9 ../../Algorithm-Evolutionary/lib);
  2         3  
12              
13             our $VERSION = sprintf "%d.%03d", q$Revision: 1.13 $ =~ /(\d+)\.(\d+)/g;
14              
15 2     2   670 use base 'Algorithm::MasterMind::Evolutionary_Base';
  2         4  
  2         990  
16              
17             use Algorithm::MasterMind qw(entropy);
18              
19             use Algorithm::Evolutionary qw( Individual::BitString
20             Op::EDA_step );
21              
22             sub fitness {
23             my $self = shift;
24             my $object = shift;
25             my $combination = $object->{'_str'};
26             my $matches = $self->matches( $combination );
27             $object->{'_matches'} = $matches->{'matches'};
28             my $blacks_and_whites = 1;
29             for my $r (@{$matches->{'result'}} ) {
30             $blacks_and_whites += $r->{'blacks'} + $r->{'whites'}+ $self->{'_length'}*$r->{'match'};
31             }
32             return $blacks_and_whites;
33            
34             }
35              
36              
37             sub initialize {
38             my $self = shift;
39             my $options = shift;
40             for my $o ( keys %$options ) {
41             $self->{"_$o"} = $options->{$o};
42             }
43             $self->{'_fitness'} = 'orig' if !$self->{'_fitness'};
44             $self->{'_first'} = 'orig' if !$self->{'_first'};
45             my $length = $options->{'length'};
46              
47             #----------------------------------------------------------#
48             # #
49             my $fitness;
50             if ( $self->{'_fitness'} eq 'orig' ) {
51             $fitness = sub { $self->fitness_orig(@_) };
52             } elsif ( $self->{'_fitness'} eq 'naive' ) {
53             $fitness = sub { $self->fitness(@_) };
54             } elsif ( $self->{'_fitness'} eq 'compress' ) {
55             $fitness = sub { $self->fitness_compress(@_) };
56             }
57              
58             #EDA itself
59             my $eda = new Algorithm::Evolutionary::Op::EDA_step( $fitness,
60             $options->{'replacement_rate'},
61             $options->{'pop_size'},
62             $self->{'_alphabet'});
63             $self->{'_fitness'} = $fitness;
64             $self->{'_eda'} = $eda;
65              
66            
67             }
68              
69             sub issue_first {
70             my $self = shift;
71             my ( $i, $string);
72             my @alphabet = @{ $self->{'_alphabet'}};
73             my $half = @alphabet/2;
74             if ( $self->{'_first'} eq 'orig' ) {
75             for ( $i = 0; $i < $self->{'_length'}; $i ++ ) {
76             $string .= $alphabet[ $i % $half ]; # Recommendation Knuth
77             }
78             } elsif ( $self->{'_first'} eq 'half' ) {
79             for ( $i = 0; $i < $self->{'_length'}; $i ++ ) {
80             $string .= $alphabet[ $i /2 ]; # Recommendation first paper
81             }
82             }
83             $self->{'_first'} = 1; # Flag to know when the second is due
84              
85             #Initialize population for next step
86             my @pop;
87             for ( 0..$self->{'_pop_size'} ) {
88             my $indi = Algorithm::Evolutionary::Individual::String->new( $self->{'_alphabet'},
89             $self->{'_length'} );
90             push( @pop, $indi );
91             }
92            
93             $self->{'_pop'}= \@pop;
94            
95             return $self->{'_last'} = $string;
96             }
97              
98             sub issue_next {
99             my $self = shift;
100             my $rules = $self->number_of_rules();
101             my ($match, $best);
102             my $pop = $self->{'_pop'};
103             my $eda = $self->{'_eda'};
104              
105             map( $_->evaluate( $self->{'_fitness'}), @$pop );
106             my @ranked_pop = sort { $b->{_fitness} <=> $a->{_fitness}; } @$pop;
107             if ( $ranked_pop[0]->{'_matches'} == $rules ) { #Already found!
108             return $self->{'_last'} = $ranked_pop[0]->{'_str'};
109             } else {
110             my $generations_passed = 0;
111             my @pop_by_matches;
112             do {
113             $eda->apply( $pop );
114             map( $_->{'_matches'} = $_->{'_matches'}?$_->{'_matches'}:-1, @$pop ); #To avoid warnings
115             @pop_by_matches = sort { $b->{'_matches'} <=> $a->{'_matches'} } @$pop;
116             $generations_passed ++;
117             $best = $pop_by_matches[0];
118             if ($generations_passed == 15 ) {
119             $eda->reset( $pop );
120             $generations_passed = 0;
121             }
122             } while ( $best->{'_matches'} < $rules );
123             return $self->{'_last'} = $best->{'_str'};
124             }
125              
126             }
127              
128             "Many blacks, 0 white"; # Magic true value required at end of module
129              
130             __END__