File Coverage

lib/Algorithm/Evolutionary/Op/Base.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1 24     24   55281 use strict; #-*-cperl-*-
  24         47  
  24         845  
2 24     24   128 use warnings;
  24         45  
  24         1381  
3              
4             =head1 NAME
5              
6             Algorithm::Evolutionary::Op::Base - Base class for Algorithm::Evolutionary operators,
7              
8             =head1 SYNOPSIS
9              
10             my $op = new Algorithm::Evolutionary::Op::Base; #Creates empty op, with rate
11              
12             my $xmlStr=<
13            
14            
15            
16             EOC
17              
18             my $ref = XMLin($xmlStr);
19             my $op = Algorithm::Evolutionary::Op::Base->fromXML( $ref ); #Takes a hash of parsed XML and turns it into an operator
20              
21             print $op->asXML(); #prints it back in XML shape
22              
23             print $op->rate(); #application rate; relative number of times it must be applied
24             print "Yes" if $op->check( 'Algorithm::Evolutionary::Individual::Bit_Vector' ); #Prints Yes, it can be applied to Bit_Vector individual
25             print $op->arity(); #Prints 1, number of operands it can be applied to
26              
27             =head1 DESCRIPTION
28              
29             Base class for operators applied to Individuals and Populations and
30             all the rest. An operator is any object with the "apply" method,
31             which does things to individuals or populations. It is intendedly
32             quite general so that any genetic or population operator can fit in.
33              
34             =head1 METHODS
35              
36             =cut
37              
38             package Algorithm::Evolutionary::Op::Base;
39              
40 24     24   160 use lib qw( ../.. ../../.. );
  24         44  
  24         255  
41              
42 24     24   37808 use Memoize;
  24         98352  
  24         2064  
43             memoize('arity'); #To speed up this frequent computation
44              
45 24     24   238 use B::Deparse; #For serializing code
  24         50  
  24         674  
46 24     24   14279 use Algorithm::Evolutionary::Utils qw(parse_xml);
  0            
  0            
47              
48             use Carp;
49             our ($VERSION) = ( '$Revision: 3.3 $ ' =~ / (\d+\.\d+)/ ) ;
50             our %parameters;
51              
52             =head2 AUTOLOAD
53              
54             Automatically define accesors for instance variables. You should
55             probably not worry about this unless you are going to subclass.
56              
57             =cut
58              
59             sub AUTOLOAD {
60             my $self = shift;
61             our $AUTOLOAD;
62             my ($method) = ($AUTOLOAD =~ /::(\w+)/);
63             my $instanceVar = "_".lcfirst($method);
64             if (defined ($self->{$instanceVar})) {
65             if ( @_ ) {
66             $self->{$instanceVar} = shift;
67             } else {
68             return $self->{$instanceVar};
69             }
70             }
71              
72             }
73              
74             =head2 new( [$priority] [,$options_hash] )
75              
76             Takes a hash with specific parameters for each subclass, creates the
77             object, and leaves subclass-specific assignments to subclasses
78              
79             =cut
80              
81             sub new {
82             my $class = shift;
83             carp "Should be called from subclasses" if ( $class eq __PACKAGE__ );
84             my $rate = shift || 1;
85             my $hash = shift; #No carp here, some operators do not need specific stuff
86             my $self = { rate => $rate,
87             _arity => eval( "\$"."$class"."::ARITY" )}; # Create a reference
88             bless $self, $class; # And bless it
89             $self->set( $hash ) if $hash ;
90             return $self;
91             }
92              
93             =head2 create( [@operator_parameters] )
94              
95             Creates an operator via its default parameters. Probably obsolete
96              
97             =cut
98              
99             sub create {
100             my $class = shift;
101             my $self;
102             for my $p ( keys %parameters ) {
103             $self->{"_$p"} = shift || $parameters{$p}; # Default
104             }
105             bless $self, $class;
106             return $self;
107             }
108              
109             =head2 fromXML()
110              
111             Takes a definition in the shape and turns it into an object,
112             if it knows how to do it. The definition must have been processed using XML::Simple.
113              
114             It parses the common part of the operator, and leaves specific parameters for the
115             subclass via the "set" method.
116              
117             =cut
118              
119             sub fromXML {
120             my $class = shift;
121             my $xml = shift || croak "XML fragment missing ";
122             my $fragment; # Inner part of the XML
123             if ( ref $xml eq '' ) { #We are receiving a string, parse it
124             $xml = parse_xml( $xml );
125             croak "Incorrect XML fragment" if !$xml->{'op'}; #
126             $fragment = $xml->{'op'};
127             } else {
128             $fragment = $xml;
129             }
130             my $rate = shift;
131             if ( !defined $rate && $fragment->{'-rate'} ) {
132             $rate = $fragment->{'-rate'};
133             }
134             my $self = { rate => $rate }; # Create a reference
135              
136             if ( $class eq __PACKAGE__ ) { #Deduct class from the XML
137             $class = $fragment->{'-name'} || shift || croak "Class name missing";
138             }
139            
140             $class = "Algorithm::Evolutionary::Op::$class" if $class !~ /Algorithm::Evolutionary/;
141             bless $self, $class; # And bless it
142            
143             my (%params, %code_fragments, %ops);
144            
145             for ( @{ (ref $fragment->{'param'} eq 'ARRAY')?
146             $fragment->{'param'}:
147             [ $fragment->{'param'}] } ) {
148             if ( defined $_->{'-value'} ) {
149             $params{$_->{'-name'}} = $_->{'-value'};
150             } elsif ( $_->{'param'} ) {
151             my %params_hash;
152             for my $p ( @{ (ref $_->{'param'} eq 'ARRAY')?
153             $_->{'param'}:
154             [ $_->{'param'}] } ) {
155             $params_hash{ $p->{'-name'}} = $p->{'-value'};
156             }
157             $params{$_->{'-name'}} = \%params_hash;
158             }
159             }
160            
161             if ($fragment->{'code'} ) {
162             $code_fragments{$fragment->{'code'}->{'-type'}} = $fragment->{'code'}->{'src'};
163             }
164            
165             for ( @{$fragment->{'op'}} ) {
166             $ops{$_->{'-name'}} = [$_->{'-rate'}, $_];
167             }
168              
169             #If the class is not loaded, we load it. The
170             eval "require $class" || croak "Can't find $class Module";
171              
172             #Let the class configure itself
173             $self->set( \%params, \%code_fragments, \%ops );
174             return $self;
175             }
176              
177              
178             =head2 asXML( [$id] )
179              
180             Prints as XML, following the EvoSpec 0.2 XML specification. Should be
181             called from derived classes, not by itself. Provides a default
182             implementation of XML serialization, with a void tag that includes the
183             name of the operator and the rate (all operators have a default
184             rate). For instance, a C operator would be serialized as C< Eop
185             name='foo' rate='1' E >.
186              
187             If there is not anything special, this takes also care of the instance
188             variables different from C: they are inserted as C within
189             the XML file. In this case, Cs are void tags; if you want
190             anything more fancy, you will have to override this method. An
191             optional ID can be used.
192              
193             =cut
194              
195             sub asXML {
196             my $self = shift;
197             my ($opName) = ( ( ref $self) =~ /::(\w+)$/ );
198             my $name = shift; #instance variable it corresponds to
199             my $str = "
200             $str .= "id ='$name' " if $name;
201             if ( $self->{rate} ) { # "Rated" ops, such as genetic ops
202             $str .= " rate='".$self->{rate}."'";
203             }
204             if (keys %$self == 1 ) {
205             $str .= " />" ; #Close void tag, only the "rate" param
206             } else {
207             $str .= " >";
208             for ( keys %$self ) {
209             next if !$self->{$_};
210             if (!/\brate\b/ ) {
211             my ($paramName) = /_(\w+)/;
212             if ( ! ref $self->{$_} ) {
213             $str .= "\n\t";
214             } elsif ( ref $self->{$_} eq 'ARRAY' ) {
215             for my $i ( @{$self->{$_}} ) {
216             $str .= $i->asXML()."\n";
217             }
218             } elsif ( ref $self->{$_} eq 'CODE' ) {
219             my $deparse = B::Deparse->new;
220             $str .="\ncoderef2text($self->{$_})."]]>\n \n";
221             } elsif ( (ref $self->{$_} ) =~ 'Algorithm::Evolutionary' ) { #Composite object, I guess...
222             $str .= $self->{$_}->asXML( $_ );
223             }
224             }
225             }
226             $str .= "\n";
227             }
228             return $str;
229             }
230              
231             =head2 rate( [$rate] )
232              
233             Gets or sets the rate of application of the operator
234              
235             =cut
236              
237             sub rate {
238             my $self = shift ;
239             $self->{rate} = shift if @_;
240             return $self;
241             }
242              
243             =head2 check()
244              
245             Check if the object the operator is applied to is in the correct
246             class.
247              
248             =cut
249              
250             sub check {
251             my $self = (ref $_[0] ) || $_[0] ;
252             my $object = $_[1];
253             my $at = eval ("\$"."$self"."::APPLIESTO");
254             return $object->isa( $at ) ;
255             }
256              
257             =head2 arity()
258              
259             Returns the arity, ie, the number of individuals it can be applied to
260              
261             =cut
262              
263             sub arity {
264             my $class = ref shift;
265             return eval( "\$"."$class"."::ARITY" );
266             }
267              
268             =head2 set( $options_hashref )
269              
270             Converts the parameters passed as hash in instance variables. Default
271             method, probably should be overriden by derived classes. If it is not,
272             it sets the instance variables by prepending a C<_> to the keys of the
273             hash. That is,
274             $op->set( { foo => 3, bar => 6} );
275             will set C<$op-E{_foo}> and C<$op-E{_bar}> to the corresponding values
276              
277             =cut
278              
279             sub set {
280             my $self = shift;
281             my $hashref = shift || croak "No params here";
282             for ( keys %$hashref ) {
283             $self->{"_$_"} = $hashref->{$_};
284             }
285             }
286              
287             =head2 Known subclasses
288              
289             This is quite incomplete. Should be either generated automatically or
290             suppressed altogether
291              
292             =over 4
293              
294             =item *
295              
296             L
297              
298             =item *
299              
300             L
301              
302             =item *
303              
304             L
305              
306             =item *
307              
308             L
309              
310             =item *
311              
312             L
313              
314             =item *
315              
316             L
317              
318             =item *
319              
320             L
321              
322             =item *
323              
324             L
325              
326             =item *
327              
328             L
329              
330             =item *
331              
332             L
333              
334              
335             =item *
336              
337             L
338              
339             =item *
340              
341             L
342              
343             =item *
344              
345             L
346              
347             =item *
348              
349             L
350              
351             =item *
352              
353             L
354              
355              
356             =back
357              
358             =head1 See Also
359              
360             The introduction to the XML format used here, L
361              
362             =head1 Copyright
363            
364             This file is released under the GPL. See the LICENSE file included in this distribution,
365             or go to http://www.fsf.org/licenses/gpl.txt
366              
367             =cut
368              
369             "What???";