File Coverage

lib/Algorithm/Evolutionary/Individual/Base.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1 36     36   1498 use strict; #-*-cperl,hi-lock,auto-fill-*-
  36         72  
  36         1551  
2 36     36   188 use warnings;
  36         64  
  36         2466  
3              
4 36     36   205 use lib qw( ../../../../lib );
  36         59  
  36         289  
5              
6             =head1 NAME
7              
8             Algorithm::Evolutionary::Individual::Base - Base class for chromosomes that knows how to build them, and has some helper methods.
9            
10             =head1 SYNOPSIS
11              
12             use Algorithm::Evolutionary::Individual::Base;
13             my $xmlStr="1010";
14             my $ref = XMLin($xmlStr);
15              
16             my $binIndi2 = Algorithm::Evolutionary::Individual::Base->fromXML( $ref ); #From XML fragment
17             print $binIndi2->asXML();
18              
19             my $indi = Algorithm::Evolutionary::Individual::Base->fromParam( $ref->{initial}{section}{indi}{param} ); #From parametric description
20              
21             $binIndi2->Fitness( 3.5 ); #Sets or gets fitness
22             print $binIndi2->Fitness();
23              
24             my $emptyIndi = new Algorithm::Evolutionary::Individual::Base;
25              
26             =head1 DESCRIPTION
27              
28             Base class for individuals, that is, "chromosomes" in evolutionary
29             computation algorithms. However, chromosomes needn't be bitstrings, so
30             the name is a bit misleading. This is, however, an "empty" base class,
31             that acts as a boilerplate for deriving others.
32              
33             =cut
34              
35             package Algorithm::Evolutionary::Individual::Base;
36              
37 36     36   43527 use Algorithm::Evolutionary::Utils qw(parse_xml);
  0            
  0            
38             use YAML qw(Dump Load LoadFile);
39             use Carp;
40              
41             our $VERSION = sprintf "%d.%03d", q$Revision: 3.2 $ =~ /(\d+)\.(\d+)/g;
42              
43             use constant MY_OPERATORS => qw(None);
44              
45             =head1 METHODS
46              
47              
48             =head2 AUTOLOAD
49              
50             Creates methods for instance variables automatically
51              
52             =cut
53              
54             sub AUTOLOAD {
55             my $self = shift;
56             my $attr = our $AUTOLOAD;
57             $attr =~ s/.*:://;
58             return unless $attr =~ /[^A-Z]/; # skip DESTROY and all-cap methods
59             my $instance_variable = "_$attr";
60             $self->{$instance_variable} = shift if @_;
61             return $self->{$instance_variable};
62             }
63              
64             =head2 new( $options )
65              
66             Creates a new Base individual of the required class, with a fitness, and sets fitnes to undef.
67             Takes as params a hash to the options of the individual, that will be passed
68             on to the object of the class when it iss initialized.
69              
70             =cut
71              
72             sub new {
73             my $class = shift;
74             if ( $class !~ /Algorithm::Evolutionary/ ) {
75             $class = "Algorithm::Evolutionary::Individual::$class";
76             }
77             my $options = shift;
78             my $self = { _fitness => undef }; # Avoid error
79             bless $self, $class; # And bless it
80              
81             #If the class is not loaded, we load it. The
82             if ( !$INC{"$class\.pm"} ) {
83             eval "require $class" || croak "Can't find $class Module";
84             }
85             if ( $options ) {
86             $self->set( $options );
87             }
88              
89             return $self;
90             }
91              
92             =head2 create( $ref_to_hash )
93              
94             Creates a new individual, but uses a different interface: takes a
95             ref-to-hash, with named parameters, which gives it a common interface
96             to all the hierarchy. The main difference with respect to new is that
97             after creation, it is initialized with random values.
98              
99             =cut
100              
101             sub create {
102             my $class = shift;
103             my $ref = shift || croak "Can't find the parameters hash";
104             my $self = Algorithm::Evolutionary::Individual::Base::new( $class, $ref );
105             $self->randomize();
106             return $self;
107             }
108              
109             =head2 set( $ref_to_hash )
110              
111             Sets values of an individual; takes a hash as input. Keys are prepended an
112             underscore and turn into instance variables
113              
114             =cut
115              
116             sub set {
117             my $self = shift;
118             my $hash = shift || croak "No params here";
119             for ( keys %{$hash} ) {
120             $self->{"_$_"} = $hash->{$_};
121             }
122             }
123              
124             =head2 fromXML( $xml_string )
125              
126             Takes a definition in the shape .... and turns it into a bitstring,
127             if it knows how to do it. The definition must have been processed using XML::Simple. It forwards stuff it does
128             not know about to the corresponding subclass, which should implement the C method. The class it refers
129             about is Cd in runtime.
130              
131             =cut
132              
133             sub fromXML {
134             my $class = shift;
135             my $xml = shift || croak "XML fragment missing ";
136             my $fragment; # Inner part of the XML
137             if ( ref $xml eq '' ) { #We are receiving a string, parse it
138             $xml = parse_xml ($xml );
139             croak "Incorrect XML fragment" if !$xml->{'indi'}; #
140             $fragment = $xml->{'indi'};
141             } elsif ( $xml->{'indi'} ) { # parsed externally, as in general.t
142             $fragment = $xml->{'indi'};
143             } else { #parsed fragment
144             $fragment = $xml;
145             }
146              
147             my $thisClassName = $fragment->{'-type'};
148             if ( $class eq __PACKAGE__ ) { #Deduct class from the XML
149             $class = $thisClassName || shift || croak "Class name missing";
150             }
151              
152             #Calls new, adds preffix if it's not there
153             my $self = Algorithm::Evolutionary::Individual::Base::new( $class );
154             ($self->Fitness( $fragment->{'fitness'} ) ) if defined $fragment->{'fitness'};
155            
156             $class = ref $self;
157             eval "require $class" || croak "Can't find $class\.pm Module";
158             no strict qw(refs); # To be able to check if a ref exists or not
159              
160             for (@{$fragment->{'atom'}} ) {
161             $self->addAtom($_); #roundabout way of adding the content of the stuff
162             }
163             return $self;
164             }
165              
166             =head2 fromParam( $xml_fragment )
167              
168             Takes an array of params that describe the individual, and builds it, with
169             random initial values.
170              
171             Params have this shape:
172            
173            
174            
175              
176             The 'type' will show the class of the individuals that are going to
177             be created, and the rest will be type-specific, and left to the particular
178             object to interpret.
179              
180             =cut
181              
182             sub fromParam {
183             my $class = shift;
184             my $xml = shift || croak "XML fragment missing ";
185             my $thisClass;
186            
187             my %params;
188             for ( @{$xml->{'param'}} ) {
189             if ( $_->{'-name'} eq 'type' ) {
190             $thisClass = $_->{'-value'}
191             } else {
192             $params{ $_->{'-name'} } = $_->{'-value'};
193             }
194             }
195             $thisClass = "Algorithm::Evolutionary::Individual::$thisClass"
196             if $thisClass !~ /Algorithm::Evolutionary/;
197              
198             eval "require $thisClass" || croak "Can't find $class\.pm Module";
199             my $self = $thisClass->new();
200             $self->set( \%params );
201             $self->randomize();
202             return $self;
203             }
204              
205             =head2 asXML()
206              
207             Prints it as XML. The caller must close the tags.
208              
209             =cut
210              
211             sub asXML {
212             my $self = shift;
213             my ($opName) = ( ( ref $self) =~ /::(\w+)$/ );
214             my $str = "
215             if ( defined $self->{_fitness} ) {
216             $str.= "fitness='$self->{_fitness}'";
217             }
218             $str.=" />\n\t";
219             return $str;
220             }
221              
222             =head2 as_yaml()
223              
224             Prints it as YAML.
225              
226             =cut
227              
228             sub as_yaml {
229             my $self = shift;
230             return Dump($self);
231             }
232              
233             =head2 as_string()
234              
235             Prints it as a string in the most meaningful representation possible
236              
237             =cut
238              
239             sub as_string {
240             croak "This function is not defined at this level, you should override it in a subclass\n";
241             }
242              
243             =head2 as_string_with_fitness( [$separator] )
244              
245             Prints it as a string followed by fitness. Separator by default is C<;>
246              
247             =cut
248              
249             sub as_string_with_fitness {
250             my $self = shift;
251             my $separator = shift || "; ";
252             return $self->as_string().$separator.$self->Fitness();
253             }
254              
255             =head2 Atom( $index [, $value )
256              
257             Sets or gets the value of an atom. Each individual is divided in atoms, which
258             can be accessed sequentially. If that does not apply, Atom can simply return the
259             whole individual
260              
261             =cut
262              
263             sub Atom {
264             croak "This function is not defined at this level, you should override it in a subclass\n";
265             }
266              
267             =head2 Fitness( [$value] )
268              
269             Sets or gets fitness
270              
271             =cut
272              
273             sub Fitness {
274             my $self = shift;
275             if ( defined $_[0] ) {
276             $self->{_fitness} = shift;
277             }
278             return $self->{_fitness};
279             }
280              
281             =head2 my_operators()
282              
283             Operators that can act on this data structure. Returns an array with the names of the known operators
284              
285             =cut
286              
287             sub my_operators {
288             my $self = shift;
289             return $self->MY_OPERATORS;
290             }
291              
292             =head2 evaluate( $fitness )
293              
294             Evaluates using the $fitness thingy given. Can be a L object or a ref-to-sub
295              
296             =cut
297              
298             sub evaluate {
299             my $self = shift;
300             my $fitness_func = shift || croak "Need a fitness function";
301             if ( ref $fitness_func eq 'CODE' ) {
302             return $self->Fitness( $fitness_func->($self) );
303             } elsif ( ( ref $fitness_func ) =~ 'Fitness' ) {
304             return $self->Fitness( $fitness_func->apply($self) );
305             } else {
306             croak "$fitness_func can't be used to evaluate";
307             }
308              
309             }
310              
311             =head2 Chrom()
312              
313             Sets or gets the chromosome itself, that is, the data
314             structure evolved. Since each derived class has its own
315             data structure, and its own name, it is left to them to return
316             it
317              
318             =cut
319              
320             sub Chrom {
321             my $self = shift;
322             croak "To be implemented in derived classes!";
323             }
324              
325             =head2 size()
326              
327             OK, OK, this is utter inconsistence, but I'll re-consistence it
328             eventually. Returns a meaningful size; but should be reimplemented
329             by siblings
330              
331             =cut
332              
333             sub size() {
334             croak "To be implemented in derived classes!";
335             }
336              
337             =head1 Known subclasses
338              
339             =over 4
340              
341             =item *
342              
343             L
344              
345             =item *
346              
347             L
348              
349             =item *
350              
351             L
352              
353             =item *
354              
355             L
356              
357             =back
358              
359             =head1 Copyright
360            
361             This file is released under the GPL. See the LICENSE file included in this distribution,
362             or go to http://www.fsf.org/licenses/gpl.txt
363              
364             CVS Info: $Date: 2009/11/17 19:19:41 $
365             $Header: /media/Backup/Repos/opeal/opeal/Algorithm-Evolutionary/lib/Algorithm/Evolutionary/Individual/Base.pm,v 3.2 2009/11/17 19:19:41 jmerelo Exp $
366             $Author: jmerelo $
367             $Revision: 3.2 $
368             $Name $
369              
370             =cut
371              
372             "The plain truth";
373