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