use strict;
use warnings;
=head1 NAME
Algorithm::Evolutionary::Op::CX (Cycle crossover) - 2-point crossover operator; Builds offspreing in such a way
that each gene comes from one of the parents. Preserves the absolute position of the elements
in the parent sequence
=head1 SYNOPSIS
my $xmlStr3=<
EOC
my $ref3 = XMLin($xmlStr3);
my $op3 = Algorithm::Evolutionary::Op::Base->fromXML( $ref3 );
print $op3->asXML(), "\n";
my $op4 = new Algorithm::Evolutionary::Op::CX 3;
my $indi = new Algorithm::Evolutionary::Individual::Vector 10;
my $indi2 = $indi->clone();
my $indi3 = $indi->clone();
$op3->apply( $indi2, $indi3 );
=head1 Base Class
L
=head1 DESCRIPTION
Cycle Crossover operator for a GA. It applies to chromosomes that are
a permutation of each other; even as the class it applies to is
L, it will issue lots of
"La jodimos!" messages if the parents do not fulfill this condition.
Some information on this operator can be obtained from
L
=head1 METHODS
=cut
package Algorithm::Evolutionary::Op::CX;
our ($VERSION) = ( '$Revision: 1.3 $ ' =~ /(\d+\.\d+)/ );
use Carp;
use Algorithm::Evolutionary::Op::Base;
our @ISA = ('Algorithm::Evolutionary::Op::Base');
#Class-wide constants
our $APPLIESTO = 'Algorithm::Evolutionary::Individual::Vector';
our $ARITY = 2;
=head2 new
Creates a new Algorithm::Evolutionary::Op::CX operator.
=cut
sub new {
my $class = shift;
my $hash = { numPoints => shift || 2 };
my $rate = shift || 1;
my $self = Algorithm::Evolutionary::Op::Base::new( __PACKAGE__, $rate, $hash );
return $self;
}
=head2 create
Creates a new Algorithm::Evolutionary::Op::CX operator. But this is just to have a non-empty chromosome
=cut
sub create {
my $class = shift;
my $self;
$self->{_numPoints} = shift || 2;
bless $self, $class;
return $self;
}
=head2 apply
Applies Algorithm::Evolutionary::Op::CX operator to a "Chromosome", a bitstring, really. Can be
applied only to I with the C<_bitstring> instance variable; but
it checks before application that both operands are of type
L.
=cut
sub apply ($$;$){
my $self = shift;
my $p1 = shift || croak "No victim here!"; #first parent
my $p2 = shift || croak "No victim here!"; #second parent
my $child=$p1->clone(); #Child
my $i; #Iterator
my $j; #Iterator
my $changed;
#Check parents type and size
croak "Incorrect type ".(ref $p1) if !$self->check($p1);
croak "Incorrect type ".(ref $p2) if !$self->check($p2);
croak "Algorithm::Evolutionary::Op::CX Error: Parents don't have the same size " if ($p1->length() != $p2->length() );
my $leng=$p1->length(); #Chrom length
my $no='x';#-( $leng );#Uninitialized gene mark
#Init child
for ($i=0;$i < $leng; $i++)
{ $child->Atom($i, $no);}
my %visto;
map( $visto{$_}++,@{$p1->{_array}} );
#Build child
# print "CX \$leng = $leng\n";
$changed=$i=0;
while ($changed < $leng ) {
my $found=0;
#Looking for the next element in cycle
for ($j=0; $j < $leng ; $j++) {
if ( $p1->Atom($j) == $p2->Atom($i)) {
$found=$j;
last;
}
}
#Look if the next element in cycle was found
if ($found) {
$child->Atom($found, $p1->Atom($found));
# print "Found $found valor ", $child->Atom($found), "\n";
$i=$found;
$changed++;
}
else { #End of the cycle, get the genes from the second parent
$child->Atom(0, $p1->Atom(0) ); $changed++;
for ($i=1;( $i < $leng ) && ( $changed < $leng ) ; $i++) {
if ($child->Atom($i) eq $no ) {
# print "Cambiando $i valor ", $p2->Atom($i), "\n";
$child->Atom($i,$p2->Atom($i));
$changed++;
}
}
}
}#End-while
map( $visto{$_}++,@{$child->{_array}} );
for (keys %visto) {
if ($visto{$_} > 2 ) {
print "La jodimos!\n";
}
if ($visto{$_} < 2 ) {
print "La jodimos!\n";
}
#print "$_ visto $visto{$_}\n";
};
for ( $i = 0; $i < $leng; $i ++ ) {
if ($child->Atom($i) eq $no ){
print "Messed up!\n";
}
}
return $child; #return Child
}
=head1 Copyright
This file is released under the GPL. See the LICENSE file included in this distribution,
or go to http://www.fsf.org/licenses/gpl.txt
CVS Info: $Date: 2002/11/19 12:26:49 $
$Header: /cvsroot/opeal/opeal/Algorithm/Evolutionary/Op/CX.pm,v 1.3 2002/11/19 12:26:49 jmerelo Exp $
$Author: jmerelo $
$Revision: 1.3 $
$Name $
=cut