1

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.

1
  • This would really benefit from some sample data. And using strict and warnings. As it is, it's really hard to tell if there's a even a problem in this piece of code you've quoted, as it could easily just not be there. Commented Oct 21, 2015 at 15:44

3 Answers 3

2
$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.

Sign up to request clarification or add additional context in comments.

Comments

2

I think your problem will probably be this:

$p0e[$i] = $p[$f{"rank"}{$r}]; # save chromosome

Because it looks like @p is a multi-dimensional array.

The problem is - the way perl 'does' multi dimensional arrays is via arrays of references. So if you copy an inner array, you do so by reference.

E.g.:

#!c:\Strawberry\perl\bin
use strict;
use warnings;

use Data::Dumper;

my @list = ( [ 1, 2, 3 ],
             [ 4, 5, 6 ],
             [ 7, 8, 9 ], );

             print Dumper \@list; 

my @other_list;
push ( @other_list, @list[0,1] ); #make a sub list of two rows;
print Dumper \@other_list; 


### all looks good.
## but if we:

print "List:\n";
print join ("\n",@list),"\n";
print "Other List:\n";
print join ("\n", @other_list),"\n";

$list[1][1] = 9;

print Dumper \@other_list;

You will see that by changing an element in @list we also modify @other_list - and if we just print them we get:

List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)
ARRAY(0x12cf024)
Other List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)

Note the duplicate numbers - that means you have the same reference.

The easiest way of working around this is by using [] judicously:

push ( @other_list, [@{$list[0]}], [@{$list[1]}] ); #make a sub list of two rows;

This will then insert anonymous arrays (new ones) containing the dereferenced elements of the list.

Whilst we're at it though - please turn on strict and warnings. They will save you a lot of pain in the long run.

Comments

0

That's because it's an array of arrays. The first level array stores only references to the inner arrays, if you modify the inner array, it's changed in both arrays - they both refer to the same array. Clone the deep copy instead of creating a shallow one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.