I have two global multidimensional arrays @p
and @p0e
in Perl. This is part of a genetic algorith where I want to save certain keys from @p
to @p0e
. Modifications are then made to @p
. There are several subroutines that make modifications to @p
, but there's a certain subroutine where on occasion (not on every iteration) a modification to @p
also leads to @p0e
being modified (it receives the same keys) although @p0e
should not be affected.
# this is the sub where part of @p is copied to @p0e
sub saveElite {
@p0e = (); my $i = 0;
foreach my $r (sort({$a<=>$b} keys $f{"rank"})) {
if ($i<$elN) {
$p0e[$i] = $p[$f{"rank"}{$r}]; # save chromosome
}
else {last;}
$i++;
}
}
# this is the sub that then sometimes changes @p0e
sub mutation {
for (my $i=0; $i<@p; $i++) {
for (my $j=0; $j<@{$p[$i]}; $j++) {
if (rand(1)<=$mut) { # mutation
$p[$i][$j] = mutate($p[$i][$j]);
}
}
}
}
I thought maybe I'd somehow created a reference to the original array rather than a copy, but because this unexpected behaviour doesn't happen on every iteration this shouldn't be the case.
$j = $f{"rank"}{$r};
$p0e[$i] = $p[$j];
$p[$j]
is an array reference, which you can think of as pointing to a particular list of data at a particular memory address. The assignment to $p0e[$i]
also tells Perl to let the $i
-th row of @p0e
also refer to that same block of memory. So when you later make a change to $p0e[$i][$k]
, you'll find the value of $p[$j][$k]
has changed too.
To fix this, you'll want to assign a copy of $p[$j]
. Here is one way you can do that:
$p0e[$i] = [ @{$p[$j]} ];
@{$p[$j]}
deferences the array reference and [...]
creates a new reference for it, so after this statement $p0e[$i]
will have the same contents with the same values as $p[$j]
but point to a different block of memory.